promise用法_Promise的秘密

寫在前面

本篇文章將會帶大家從分解promise入手,一步步實現一個promise。但閱讀之前需要比較熟練地了解了解用法,結合用法看文章可能更容易理解。

結構

先看一下簡單的用法。

const promise = new Promise((resolve, reject) => {setTimeout(() => {resolve('success')})
})
.then(value => { ... }, reason => { ... })
.catch(error => { ... })

Promise的構造函數接收了一個回調,這個回調就是下面要講到的執行器,執行器的參數resolve, reject也是兩個函數,

負責改變promise實例的狀態和它的值,then函數中的回調在狀態改變后執行。

注意:不是then函數在狀態改變后執行,而是then中的回調函數在狀態改變后執行。then方法會將其中的回調放入執行隊列,promise的狀態改變后再將隊列中的函數一一執行。

如果要實現一個最簡單的promise類,內部結構都要包含什么呢?

  • 狀態:fulfiled、rejected、pending。
  • 值:promise的值。
  • 執行器:提供改變promise狀態的入口。
  • resolve和reject方法:前者將promise改變為fulfiled,后者將其改變為rejected。可以在執行器內根據實際業務來控制是resolve或reject。
  • then方法:接收兩個回調,onFulfilled, onRejected。分別在promise狀態變為fulfiled或rejected后執行,這里涉及到將回調注冊進兩個執。行隊列的操作,后文會講到。
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'class NewPromise {constructor(handler) {this.state = PENDINGthis.value = undefinedthis.successCallback = []this.failureCallback = []try {handler(this.resolve.bind(this), this.reject.bind(this))} catch (e) {this.reject(e)}}// resolve和reject方法resolve(value) { ... }reject(reason) { ... }// then方法then(onFulfilled, onRejected) { ... }
}

結構中的每個部分是如何實現的呢?

Promise的執行器

執行器是我們初始化promise時候傳入的回調,是我們操作promise的入口,所以執行器的實現不復雜,也就是將我們傳入的回調執行一下。

class NewPromise {...handler(resolve.bind(this), reject.bind(this))...
}

實際上,執行器會接受兩個回調,resolve和reject。它們真正起到改變promise狀態的作用。

resolve和reject

實際上是兩個函數,所做的事情不復雜:

  • 改變promise的狀態
  • 將接收的值作為promise的value
  • 依次執行then中注冊的回調
const PENDING = 'pending'
const FULFILLED = 'fulfiled'
const REJECTED = 'rejected'class NewPromise {constructor(handler) {this.state = PENDINGthis.value = undefined// 兩個隊列,后面會講到this.successCallback = []this.failureCallback = []try {// 執行器,由于resolve和reject中用到了this,這里需要bind一下handler(this.resolve.bind(this), this.reject.bind(this))} catch (e) {this.reject(e)}}resolve(value) {if (this.state !== PENDING) returnthis.state = FULFILLEDthis.value = value// 用setTimeout模擬異步方式setTimeout(() => {this.successCallback.forEach(item => {item(value)})})}reject(reason) {if (this.state !== PENDING) returnthis.state = REJECTEDthis.value = reasonsetTimeout(() => {this.failureCallback.forEach(item => {setTimeout(item(reason))})})}
}

看一下它們的實現,改變狀態、賦值value,最重要的一點:循環執行then方法注冊到隊列中的回調。而規范中要求回調以異步方式執行,保證在執行所有的回調之前,所有回調已經通過then注冊完成,所以這里用setTimeout模擬了一下。

then方法:

(翻譯整理自Promise/A+ 規范)
promise必須提供then方法來訪問這個promise當前或者最終的值。


then方法有兩個參數:onFulfilled, onRejected,都是可選的。關于這兩個參數,這里有幾個規則:

onFulfilled, onRejected都不是函數的時候,必須被忽略

實際上忽略的意思也就是如果不是函數,默認給它賦值成函數,返回值為then所屬的promise的值。這樣是做是為了在then()函數未傳回調的時候,可以將promise的值傳遞下去。場景如下:

promise(resolve => resolve('success')).then().then(function(value) {console.log(value)})

具體實現上,在它不是函數的時候可以給它賦值一個默認函數,也可以直接調用新返回的promise中的resolve或reject將值傳下去,來達到忽略的效果。

onFulfilled是函數的時候

  • 必須在當前的promise的狀態變為fulfilled的時候被調用,promise被resolve的值也就是它的第一個參數
  • 不能在fulfilled之前被調用。
  • 最多只能被調用一次。

onRejected是函數的時候

  • 必須在當前的promise的狀態變為rejected的時候被調用,promise被reject的值也就是它的第一個參數。不能在rejected之前被調用。
  • 最多只能被調用一次。

then可能會被調用多次

  • 當promise狀態變為fulfilled,所有onFulfilled將會按照最開始在then方法中注冊的順序去調用
  • 當promise狀態變為rejected,所有onRejected將會按照最開始在then方法中注冊的順序去調用
    就像下邊這樣:
  const promise = new Promise((resolve, reject) => {setTimeout(() => resolve('success'))})promise.then(res => {console.log(res, '第一次');})promise.then(res => {console.log(res, '第二次');})

這是fulfilled的情況,rejected的情況相同。

鑒于這種情況,需要在我們實現的promise內部維護兩個隊列,隊列中的元素是then方法內的回調函數(onFulfilled, onRejected),每調用一次then,
就向隊列中push一個回調,它們會在promise狀態改變時被依次執行。

返回一個promise,便于鏈式調用

 promise2 = promise1.then(onFulfilled, onRejected);

then返回的promise(也就是promise2)的狀態,取決于其回調函數(onFulfilled或onRejected)的返回值或者promise1的狀態,具體表現為:

  • onFulfilled或onRejected的返回值是一個值x,那么promise2的狀態為resolve,值為x
  • 如果onFulfilled或onRejected執行出錯,并拋出了錯誤對象e,那么promise2的狀態為rejected,值為這個錯誤對象e
  • 如果onFulfilled不是一個函數,但promise1狀態變為fulfilled,那么promise2狀態也為fulfilled,值與promise1相同
  • 如果onRejected不是一個函數,但promise1狀態變為rejected,那么promise2狀態也為rejected,值與promise1相同(這個值是作為promise2的reason)

實現

上面我們認識了then方法,結合定義和平時的用法可以猜測出我們自己實現的promise內的then方法需要做下邊幾件事:

  • 返回一個新的promise實例
  • then所屬的Promise在pending狀態,將then的回調(onFulfilled, onRejected)分別放入執行隊列等待執行,而這兩個隊列內的函數只有在then所屬的promise狀態被改變的時候執行。保證了規范中的onFulfilled, onRejected的執行時機。
  • then所屬的Promise狀態不為pending時,執行隊列中的回調開始依次執行,然后根據已經改變的狀態以及回調的返回值來決定新的promise的狀態
    • 舉例來說:
      ```
      const promise1 = new Promise((resolve, reject) =>{ … })
      const promise2 = promise1.then(value => {
      return 'success'
      }, reason => {
      return 'failed'
      })
      ```
      假設promise1被resolve了,由于then中傳入了代表onFulfilled的回調并且返回值為success,那么promise2會被resolve,值為success。
      假設promise2被reject了,由于then中傳入了代表onRejected的回調并且返回值為failed,那么promise2會被reject,reason是failed。

下面一步步來實現then方法,先上結構:

class NewPromise {constructor(handler) {this.state = PENDINGthis.value = undefined// 兩個隊列,存放onFulfiled 和 onRejectedthis.successCallback = []this.failureCallback = []try {handler(this.resolve.bind(this), this.reject.bind(this))} catch (e) {this.reject(e)}}then(onFulfilled, onRejected) {return new NewPromise((resolveNext, rejectNext) => {// pengding狀態向隊列中注冊回調if (state === PENDING) {successCallback.push(onFulfilled)failureCallback.push(onRejected)}// 要保證在當前promise狀態改變之后,再去通過resolveNext或者rejectNext改變新的promise的狀態if (state === FULFILLED) {resolveNext(value)}if (state === REJECTED) {rejectNext(value)}})}
}

上面的結構基本實現了then函數的大概邏輯,但是沒有實現根據onFulfilled, onRejected兩個回調的執行結果來決定新的promise的狀態的效果,只是將他們分別放到了各自的執行隊列中去。

最終then返回的promise的狀態和onFulfilled, onRejected的執行結果有關。我根據規范和實際情況整理了一張圖:

1d9635585569e8f0651e89d981ebaca6.png

然后讓我們用代碼來實現它(單以onFulfilled的執行情況舉例)

    try {// 正常情況if (typeof onFulfilled !== 'function') {// 不是函數,直接忽略,將then所屬的promise作為then返回的promise的值resolve來做到值的傳遞resolveNext(value)} else {// 獲取then函數回調的執行結果const res = onFulfilled(value)if (res instanceof NewPromise) {// 當執行結果返回的是一個promise實例,等待這個promise狀態改變后再改變then返回的promise的狀態res.then(resolveNext, rejectNext)} else {// 當返回值是普通值,將其作為新promise的值resolveresolveNext(res)}}} catch (e) {// 出現異常,新promise的狀態變為rejected,reason就是錯誤對象rejectNext(e)}

整個這一部分,需要放入隊列中等待then所屬的promise狀態改變再執行,從而改變then返回的promise的狀態。所以,我們需要將這一塊包裝起來。整合起來就是:

class NewPromise {constructor(handler) {this.state = PENDINGthis.value = undefined// 兩個隊列,存放onFulfiled 和 onRejectedthis.successCallback = []this.failureCallback = []try {handler(this.resolve.bind(this), this.reject.bind(this))} catch (e) {this.reject(e)}}then(onFulfilled, onRejected) {const { state, value } = thisreturn new NewPromise((resolveNext, rejectNext) => {const resolveNewPromise = value => {try {// 正常情況if (typeof onFulfilled !== 'function') {// 不是函數,直接忽略,將then所屬的promise作為then返回的promise的值resolve來做到值的傳遞resolveNext(value)} else {// 獲取then函數回調的執行結果const res = onFulfilled(value)if (res instanceof NewPromise) {// 當執行結果返回的是一個promise實例,等待這個promise狀態改變后再改變then返回的promise的狀態res.then(resolveNext, rejectNext)} else {// 當返回值是普通值,將其作為新promise的值resolveresolveNext(res)}}} catch (e) {// 出現異常,新promise的狀態變為rejected,reason就是錯誤對象rejectNext(e)}}const rejectNewPromise = reason => {try {// 正常情況if (typeof onRejected !== 'function') {// 不是函數,直接忽略,將then所屬的promise作為then返回的promise的值reject來做到值的傳遞rejectNext(reason)} else {// 獲取then函數回調的執行結果const res = onRejected(reason)if (res instanceof NewPromise) {// 當執行結果返回的是一個promise實例,等待這個promise狀態改變后再改變then返回的promise的狀態res.then(resolveNext, rejectNext)} else {// 當返回值是普通值,將其作為新promise的值rejectrejectNext(res)}}} catch (e) {// 出現異常,新promise的狀態變為rejected,reason就是錯誤對象rejectNext(e)}}if (state === PENDING) {this.successCallback.push(resolveNewPromise)this.failureCallback.push(rejectNewPromise)}// 要保證在當前promise狀態改變之后,再去改變新的promise的狀態if (state === FULFILLED) {resolveNewPromise(value)}if (state === REJECTED) {rejectNewPromise(value)}})}
}

我們在自己的實現中是定義了兩個數組作為任務隊列存放then注冊的回調,而實際的promise中,
then方法是將回調注冊到微任務隊列中。等到promise狀態改變,執行微任務隊列中的任務。微任務在概念上可以認為是異步任務,這也印證了規范中then的回調必須
異步執行的說法。關于事件循環的一些知識點,我總結過一篇文章,今天,我明白了JS事件循環機制

catch函數

catch函數是用來處理異常的,當promise狀態變為rejected的時候,捕獲到錯誤原因。那么假設不用catch,也可以在then函數的第二個回調中捕獲這個錯誤。


而且catch返回的是一個promise,所以與調用Promise.prototype.then(undefined, onRejected)的行為是一樣的。

catch(onRejected) {return this.then(undefined, onRejected)
}

resolve方法

Promise.resolve(value)返回的是一個promise對象,用于將傳入的值value包裝為promise對象。

那這樣做有什么意義呢?實際上value可能是一個不確定的值,可能是promise也可能不是,沒準可以調用then方法,也沒準不可以。但是可以通過resolve方法將行為統一起來。

const promise = function() {if (shouldBePromise) {return new Promise(function(resolve, reject) {resolve('ok')})}return 'ok'
}
promise().then(() => {...
})

promise返回的結果取決于shouldBePromise,假設shouldBePromise為false,那么promise就返回了字符串ok,下邊就不能調用then方法。


這個時候可以用Promise().resolve包起來,這樣promise返回的始終是一個promise實例,保證了then方法的順利調用。

Promise.resolve(promise()).then(() => {...
})

總結一下特點:Promise.resolve的參數如果:

  • 不傳,返回一個resolved狀態的Promise
  • 是一個thenable對象(即帶有"then"方法),返回的Promise的狀態將在這個對象狀態改變時改變,并且與該對象的狀態保持一致
  • 是普通值,返回一個resolved狀態的Promise,該promise的值為這個普通值
  • 是一個Promise對象,返回這個對象
  static resolve(value) {// value不存在,直接返回一個resolved狀態的promiseif (!value) {return new NewPromise(function (resolve) {resolve()})}// value是promise實例,直接返回// 在這里需要首先判斷是否是promise實例,再進行下邊的判斷// 因為我們自己構造的promise也是是object,也有then方法if (value instanceof NewPromise) {return value}// 是thenable對象,返回的新的promise實例需要在value狀態改變后再改變,且狀態跟隨value的狀態if (typeof value === 'object' && typeof value.then === 'function') {return new NewPromise((resolve, reject) => {value.then(resolve, reject)})}// value是普通值,返回新的promise并resolve這個普通值return new NewPromise(resolve => {resolve(value)})}

reject方法

reject方法對比resolve相對簡單,它總是返回一個reject的promise對象,reject的原因是我們傳入的reason。

  static reject(reason) {return new NewPromise((resolve, reject) => {reject(reason)})}

finally方法

返回的是一個promise,作用是在promise結束時,無論結果是fulfilled或者是rejected,都會執行回調函數。返回的新promise的狀態和值取決于原來的promise。

finally(callback) {// 返回值是promise對象,回調在then中執行,也就符合了promise結束后調用的原則return this.then(// then方法的onFulfiled 和 onRejected都會被傳入,保證無論resolved或rejected都會被執行// 獲取到promise執行成功的結果,將這個結果作為返回的新promise的值res => NewPromise.resolve(callback()).then(() => {return res}),// 獲取執行失敗的結果。原理同上error => NewPromise.resolve(callback()).then(() => {throw error}))
}

all方法

Promise.all(param) 接收一個參數數組,返回一個新的promise實例。當參數數組內的promise都resolve后或者參數內的實例執行完畢后,新返回的promise才會resolve。


數組內任何一個promise失敗(rejected),新返回的promise失敗,失敗原因就是第一個失敗的promise的結果。

const p1 = Promise.resolve(1),
coint p2 = Promise.resolve(2),
const p3 = Promise.resolve(3);
Promise.all([p1, p2, p3]).then(function (results) {console.log(results);  // [1, 2, 3]
});

由此可知,all方法需要返回一個新的promise實例,然后根據接收的參數數組執行情況,控制新的promise實例的狀態與值。

  static all(instanceList) {return new NewPromise((resolve, reject) => {// 定義存放結果的數組const results = []let count = 0if (instanceList.length === 0) {resolve(results)return}instanceList.forEach((item, index) => {// 由于實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層this.resolve(item).then(res => {results[index] = rescount++// 當都執行完,resolve新返回的promiseif (count === instanceList.length) {resolve(results)}}, error => {// 一旦有一個出錯,就reject新返回的promisereject(error)})})})}

實現之后可以清楚的看到,all方法會并行執行所有promise,結果按傳入的promise數組的順序輸出。這讓我想起了以前面試碰到的一個題目:并發所有請求,按順序輸出。可以用Promise.all實現。但實際上會有請求失敗的情況,所以更好的方式是下邊要講到的Promise.allSettled。

allSettled方法

如果說finally提供了在單個promise是否成功都需要執行代碼提供了一種方式,那么allSettled就是為多個promise是否成功的場景提供了同樣的操作方式。

Promise.allSettled()方法返回一個promise,該promise在所有給定的promise已被解析或被拒絕后解析,并且每個對象都描述每個promise的結果。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];Promise.allSettled(promises).then((results) => results.forEach((result) => console.log(result.status)));
// expected output:
// "fulfilled"
// "rejected"

不同于Promise.all的一旦有一個執行失敗,就無法獲得所有promise都執行完成的時間點的特點。無論某個promise成功與否,一旦所有的promise都完成,就可以獲得這個時間點。因為其返回的新的promise,總是被resolve的,并且值是所有promise執行結果的描述。

[{"status":"rejected","reason":"失敗"},{"status":"fulfiled","value":"成功"}
]

要實現它,需要在每個promise執行的時候把結果記錄下來放進一個數組內,最后在所有promise執行完成后,resolve結果數組,改變返回的新的promise的狀態。

  static allSettled(instanceList) {return new NewPromise((resolve, reject) => {const results = []let count = 0if (instanceList.length === 0) {resolve([])return}// 定義一個函數,來生成結果數組const generateResult = (result, i) => {count++results[i] = result// 一旦全部執行完成,resolve新返回的promiseif (count === instanceList.length) {resolve(results)}}instanceList.forEach((item, index) => {// 在每個promise完成后將狀態記錄到結果數組中this.resolve(item).then(value => {generateResult({status: FULFILLED,value}, index)},reason => {generateResult({status: REJECTED,reason}, index)})})})}

race方法

與all方法類似,接受一個實例數組為參數,返回新的promise。但區別是一旦實例數組中的某個promise解決或拒絕,返回的promise就會解決或拒絕。

  static race(instanceList) {return new NewPromise((resolve, reject) => {if (instanceList.length === 0) {resolve([])return}instanceList.forEach(item => {// 由于實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層this.resolve(item).then(res => {// 一旦有一個resolve了,那么新返回的promise狀態就被resolveresolve(res)}, error => {reject(error)})})})}

完整代碼

到此為止就實現了一個相對完整的promise,代碼如下:

class NewPromise {constructor(handler) {this.state = PENDINGthis.value = undefinedthis.successCallback = []this.failureCallback = []try {handler(this.resolve.bind(this), this.reject.bind(this))} catch (e) {// 執行器出現錯誤需要rejectthis.reject(e)}}resolve(value) {if (this.state !== PENDING) returnthis.state = FULFILLEDthis.value = value// 規范中要求then中注冊的回調以異步方式執行,保證在resolve執行所有的回調之前,// 所有回調已經通過then注冊完成setTimeout(() => {this.successCallback.forEach(item => {item(value)})})}reject(reason) {if (this.state !== PENDING) returnthis.state = REJECTEDthis.value = reasonsetTimeout(() => {this.failureCallback.forEach(item => {item(reason)})})}then(onFulfilled, onRejected) {const { state, value } = thisreturn new NewPromise((resolveNext, rejectNext) => {const resolveNewPromise = value => {try {// 正常情況if (typeof onFulfilled !== 'function') {// 不是函數,直接忽略,將then所屬的promise作為then返回的promise的值resolve來做到值的傳遞resolveNext(value)} else {// 獲取then函數回調的執行結果const res = onFulfilled(value)if (res instanceof NewPromise) {// 當執行結果返回的是一個promise實例,等待這個promise狀態改變后再改變then返回的promise的狀態res.then(resolveNext, rejectNext)} else {// 當返回值是普通值,將其作為新promise的值resolveresolveNext(res)}}} catch (e) {// 出現異常,新promise的狀態變為rejected,reason就是錯誤對象rejectNext(e)}}const rejectNewPromise = reason => {try {// 正常情況if (typeof onRejected !== 'function') {// 不是函數,直接忽略,將then所屬的promise作為then返回的promise的值reject來做到值的傳遞rejectNext(reason)} else {// 獲取then函數回調的執行結果const res = onRejected(reason)if (res instanceof NewPromise) {// 當執行結果返回的是一個promise實例,等待這個promise狀態改變后再改變then返回的promise的狀態res.then(resolveNext, rejectNext)} else {// 當返回值是普通值,將其作為新promise的值rejectrejectNext(res)}}} catch (e) {// 出現異常,新promise的狀態變為rejected,reason就是錯誤對象rejectNext(e)}}if (state === PENDING) {this.successCallback.push(resolveNewPromise)this.failureCallback.push(rejectNewPromise)}// 要保證在當前promise狀態改變之后,再去改變新的promise的狀態if (state === FULFILLED) {resolveNewPromise(value)}if (state === REJECTED) {rejectNewPromise(value)}})}catch(onRejected) {return this.then(undefined, onRejected)}finally(callback) {// 返回值是promise對象,回調在then中執行,也就符合了promise結束后調用的原則return this.then(// then方法的onFulfiled 和 onRejected都會被傳入,保證無論resolved或rejected都會被執行// 獲取到promise執行成功的結果,將這個結果作為finally返回的新的promise的值res => NewPromise.resolve(callback()).then(() => {return res}),// 獲取執行失敗的結果。原理同上error => NewPromise.resolve(callback()).then(() => {throw error}))}static allSettled(instanceList) {return new NewPromise((resolve, reject) => {const results = []let count = 0if (instanceList.length === 0) {resolve([])return}// 定義一個函數,來生成結果數組const generateResult = (result, i) => {count++results[i] = result// 一旦全部執行完成,resolve新返回的promiseif (count === instanceList.length) {resolve(results)}}instanceList.forEach((item, index) => {// 在每個promise完成后將狀態記錄到結果數組中this.resolve(item).then(value => {generateResult({status: FULFILLED,value}, index)},reason => {generateResult({status: REJECTED,reason}, index)})})})}static resolve(value) {// value不存在,直接返回一個resolved狀態的promiseif (!value) {return new NewPromise(function (resolve) {resolve()})}// value是promise實例,直接返回// 在這里需要首先判斷是否是promise實例,再進行下邊的判斷// 因為我們自己構造的promise也是是object,也有then方法if (value instanceof NewPromise) {return value}// 是thenable對象,返回的新的promise實例需要在value狀態改變后再改變,且狀態跟隨value的狀態if (typeof value === 'object' && typeof value.then === 'function') {return new NewPromise((resolve, reject) => {value.then(resolve, reject)})}// value是普通值,返回新的promise并resolve這個普通值return new NewPromise(resolve => {resolve(value)})}static reject(reason) {return new NewPromise((resolve, reject) => {reject(reason)})}static all(instanceList) {return new NewPromise((resolve, reject) => {// 定義存放結果的數組const results = []let count = 0if (instanceList.length === 0) {resolve(results)return}instanceList.forEach((item, index) => {// 由于實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層this.resolve(item).then(res => {results[index] = rescount++// 當都執行完,resolve新返回的promiseif (count === instanceList.length) {resolve(results)}}, error => {// 一旦有一個出錯,就reject新返回的promisereject(error)})})})}static race(instanceList) {return new NewPromise((resolve, reject) => {if (instanceList.length === 0) {resolve([])return}instanceList.forEach(item => {// 由于實例列表中的每個元素可能是各種各樣的,所以要用this.resolve方法包裝一層this.resolve(item).then(res => {// 一旦有一個resolve了,那么新返回的promise狀態就被resolveresolve(res)}, error => {reject(error)})})})}
}

片尾廣告

想看我寫的更多技術文章可以關注公眾號:一口一個前端

2d2b1c1a2a8a7211d0f5ed2d0b0d3d60.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/457663.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457663.shtml
英文地址,請注明出處:http://en.pswp.cn/news/457663.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringMVC視圖解析器(轉)

前言 在前一篇博客中講了SpringMVC的Controller控制器,在這篇博客中將接著介紹一下SpringMVC視圖解析器。當我們對SpringMVC控制的資源發起請求時,這些請求都會被SpringMVC的DispatcherServlet處理,接著Spring會分析看哪一個HandlerMapping定…

05_JS流程控制語句

JS流程控制語句 順序結構 選擇結構 if-else語句 var aprompt(); var bprompt(); var cprompt(); if(a && b || c){alert(); }else if(a || b || c){alert(); }else{alert(); }條件分支語句 var aprompt(); switch(a){case 1:alert("1");break;case 2:al…

ForkJoinPool 學習示例

在JAVA7之前,并行處理數據非常麻煩。第一,你得明確把包含數據的數據結構分成若干份。第二,你要將每個子部分分配給一個獨立的線程。第三,你要在恰當的時候對它們進行同步避免不希望的競爭條件,等待所有線程完成&#x…

python深入_Python深入(上)

作者:Vamei 出處:http://www.cnblogs.com/vamei 歡迎轉載,也請保留這段聲明。謝謝!到現在為止,Python學習已經可以告一段落。下面的部分,我想討論Python的高級語法和底層實現。這一部分的內容并不是使用Pyt…

06_JS對象

JS對象 創建對象 構造函數:var obj new Object()對象字面量:var obj {}; 不同:對象字面量可以在創建的同時為對象設置屬性,最后一個屬性后面不要加逗號 對象操作 添加屬性:對象名.新屬性名 值修改屬性&#xf…

BZOJ4107 : [Wf2015]Asteroids

首先將速度相減,變成A在動而B不動,若速度為0則顯然永遠不會相交。 枚舉A的每個點以及B的每條線段,計算這三個點共線的時刻。 將時刻排序,對于每個區間進行三分,用半平面交計算相交面積。 注意特判相交面積為0但是存在交…

Web Service 性能測試工具比較

背景 希望選擇一款Web Service性能測試工具,能真實模擬大量用戶訪問網站時的請求,從而獲取服務器當前的請求處理能力(請求數/秒)。以微信服務器為例,每個用戶用獨立的登錄token,做各種操作,比如…

python中的常量是什么意思_第14p,Python中的常量與注釋。

大家好,我是楊數Tos,這是《從零基礎到大神》系列課程的第14篇文章,第二階段的課程:Python基礎知識:常量與注釋。學習本課程,建議先看一遍:【計算機基礎知識】課程。一、Python中的常量1、什么是…

07_JS函數

JS函數 函數聲明 使用構造函數 var fun new Function();使用關鍵字 function 函數名(形參){// 函數體 }匿名函數 var fun1 function(){name "fun1" }函數參數 實參,形參都可以是任意數據類型,瀏覽器執行時不會檢查實參類型和數量&…

cocoapods的安裝(這真是一個神奇的東西,每次安裝的方法都不一樣,而且很容易出現各種各樣的錯誤)...

文章開始之前,建議安裝一個顯示網速的插件,不然你不知道到底有沒有下載,也讓生活有一點盼頭 1.因為眾所周知的原因(我dang的行為真的是讓人失望),先更換一下ruby鏡像源 $ gem sources --remove https://rub…

轉】MyEclipse使用總結——在MyEclipse中設置jsp頁面為默認utf-8編碼

原博文出自于:http://www.cnblogs.com/xdp-gacl/p/3496161.html        感謝! 在MyEclispe中創建Jsp頁面,Jsp頁面的默認編碼是“ISO-8859-1”,如下圖所示: 在這種編碼下編寫中文是沒有辦法保存Jsp頁面的&#…

sum怎么用python_python sum()函數和.sum(axis=0)函數的使用

參考:《Machine Learning in Action》第二章#####################################################################sum函數:sum()函數是內建函數help(sum)函數功能:返回一個數字序列(非字符串)的和,并加上參數start的值(默認為…

08_JS工廠方法和構造函數

工廠方法和構造函數 工廠方法 工廠方法用來批量產生對象 function CreatCar(name,prase){// new 一個對象var obj new Object();obj.name name;obj.parse prase;obj.print function(){console.log(this.name " : " this.parse)};// 返回對象return obj; };va…

華為機試題【10】-求數字基root

題目描述: 求整數的Root:給定正整數,求每位數字之和;如果和不是一位數,則重復; 輸入:輸入任意一個或多個整數 輸出:輸出各位數字之和,直到和為個位數為止(輸入異常,則返回-1),多行,每行對應一個輸入數據的結果。 樣例…

國內開源鏡像站

搜狐開源鏡像站:http://mirrors.sohu.com/ 網易開源鏡像站:http://mirrors.163.com/開源中國:http://mirrors.oschina.net/首都在線科技股份有限公司:http://mirrors.yun-idc.com/阿里云開源鏡像:http://mirrors.aliyu…

python update skeleton 不自動_python編程筆記(1)-數據類型

斷斷續續學了一些,但是后邊一直沒有使用,就又忘記了。為了縮短學習周期,這次學習的方法:先學主要框架(數據類型、條件、循環、函數、類、numpy、pandas、sklearn),后期直接看朋友code 實操了&am…

09_JS原型對象

原型對象 在構造函數中,同一類相同的方法可以直接寫在構造函數里,但這樣每實例化一個對象都會產生一個新的該方法,但其實這個方法都是一樣的,這樣會浪費大量空間,另外,可以將相同的方法寫在構造函數外&…

[改善Java代碼]非穩定排序推薦使用List

我們知道Set與List的最大區別就是Set中的元素不可以重復(這個重復指的equals方法的返回值相等),其他方面則沒有太大的區別了,在Set的實現類中有一個比較常用的類需要了解一下:TreeSet,該類實現了類默認排序…

如何訪問另一臺電腦的共享文件夾_如何遠程控制另一臺電腦

在工作中,我們時常需要遠程控制一下另一臺電腦,如果這兩臺計算機在局域網內可以通過遠程桌面輕松實現,如果這兩臺計算機不在局域網內則通常需要借助第三方軟件來實現。遠程桌面使用分三步:1、被控制端要開啟遠程桌面功能&#xff…

10_JS數組

JS 數組 以索引為鍵的對象&#xff0c;性能高于對象 創建 new Array() var arr Array() for(var i 0;i<5;i){arr[i] i; };var arr Array(1,2,3,4,5,6)數組字面量 var arr [2,3,4,5,6,7,8];不同&#xff1a;傳入一個整數時&#xff0c;new把這個數當作數組長度&…