/*Promise對象是由一個構造函數生成實例,接受函數爲參數 函數的參數爲resolve和reject。這二者,也是函數*/ var promise = new Promise ( function(resolve , reject){ /*一些異步操做*/ if(/*異步操做成功*/){ //當調用resolve函數的時候,Promise對象狀態由,Pending → Fulfilled //將value值進行傳遞(通常是異步操做成功後的結果) resolve(value) } else { //當調用reject函數的時候,Promise對象狀態由,Pending → Rejected //將error值進行傳遞 reject(error) } })
整體上來講,Promise對象,更像是一個事件的容器,但Promise對象狀態的改變並不受事件的完成而完成,而是由參數函數中的 resolve 和 reject 函數來指定它何時改變狀態。數組
好比下面代碼:promise
var promise = new Promise ( function(resolve , reject){ let i = 0//標記事件已完成,傳字符串resolved值給.then()處理 resolve(i)
i += 1 }) .then( //then方法是指,當Promise狀態由Pending改變爲Resolved時,當即調用 (value) = > { console.log(value) } )
---------------------------------------------------------------
最後輸出:
0
then()方法下面會繼續講,問題來了,上面代碼「 i += 1」是否會運行呢?再看異步
var promise = new Promise ( function(resolve , reject){ resolve() console.log('A') setTimeout(() => { console.log('B') }, 3000) }) .then(() = > { console.log('Resolved') }) --------------------------------------------------------------- 前後輸出: A Resolved B //3000ms後輸出B
Promise對象在狀態改變後,內部的代碼仍是會運行。當內部同步任務所有執行完成後,再調用then()方法。所以前兩行最早輸出的是‘A’和‘Resolved’,因爲B是一個異步事件,因此在3000ms後被調用輸出。函數
若是想在狀態改變後直接結束,不執行以後的語句,最好不要將異步操做放在狀態改變語句以後!固然也能夠這樣:spa
var promise = new Promise ( function(resolve , reject){ //在前面加上return return resolve() console.log('A') setTimeout(() => { console.log('B') }, 3000) }) .then(() = > { console.log('Resolved') }) --------------------------------------------------------------- 最後只輸出: Resolved
顧名思義,Promise實例狀態改變後,要作什麼。該方法爲其添加了回調函數。Promise實例有兩種狀態,天然也提供了兩種回調(Resolved 和 Rejected)prototype
上面已經簡單涉及了該方法,這裏整理一下:code
var promise = new Promise ( function(resolve , reject){ //作些什麼... if(/*異步操做成功*/){ resolve(value) } else { reject(error) } }) .then( //then方法接受兩個回調函數爲參數,如下 //第一個Promise實例變爲Resolved狀態調用 //函數中的參數value,接受Promise實例中resolve(value)傳遞的value值 (value) => { /*success*/ }, //(可選)第二個Promise實例變爲Rejected狀態調用 ////函數中的參數error,接受Promise實例中reject(error)傳遞的error值 (error) = > { /*failure*/ } )
上面說了then方法返回一個新的Promise實例,那麼就能夠promise.then().then().then().then().then().....這樣的鏈式調用了。對象
var promise = new Promise ( function(resolve , reject){ resolve(A) }) .then( (value) => { //此處參數 value 接受 resolve(A) 中的傳遞值 A //輸出A console.log(value) return B }).then( (value) => { //此處參數 value 接受上一級then()方法中return的值 //輸出B console.log(value) }).then( (value) => { //上一個then方法無return時 //輸出undefined console.log(value) }) ----------------------------------------------------------------- 前後在控制檯上輸出: A B undefined
若then()方法中傳入的不是函數,則在鏈式調用中,此then()方法會被忽略,值會傳入下一個then方法中blog
var promise = new Promise ( function(resolve , reject){ resolve(A) }) .then(1) //這個then方法被忽略 .then( (value) => {console.log(value)} ) ----------------------------------------------------------------- 控制檯上輸出: A
通常應用以下事件
var promise = new Promise ( function(resolve , reject){ if(/*異步操做成功*/){ resolve(value)} else { reject(new Error ('promise'))} }) .then( (value)=>{ if(/*異步操做成功*/){ return A } else { throw new Error('error_A') } }).then( (value)=>{ if(/*異步操做成功*/){ return B } else { throw new Error('error_B') } }).then( (value)=>{ if(/*異步操做成功*/){return C } else { throw new Error('error_C') } }).catch( (error)=>{ /*此處catch捕獲以上從Promise對象到任意then方法所拋出的錯誤*/ console.log(error) //catch只能捕獲被調用以前拋出的錯誤,以後的錯誤如'error_D'就沒法捕獲 }).then( (value)=>{ //上面的catch返回一個Promise對象所以能夠繼續調用then方法 if(/*異步操做成功*/){return D } else { throw new Error('error_D') } })
將多個Promise實例包裝,而且返回一個新的Promise實例
當包裝中全部的Promise狀態都變爲Resolved時,返回結果數組,數組中返回值的順序安裝包裝的數據排列
Promise.all([ promise_A, promise_B, promise_C ]).then(result=>{ console.log(result) }) --------------------------- //當promise_A,promise_B,promise_C狀態都爲Resolved時,result輸出一個結果數組: [result_A,result_B,resultC]
當Promise集合中有一個Promise最終狀態爲Rejected,就會被Promise.all()的catch方法進行捕獲
Promise.all([ new Promise((resolve, reject) => { setTimeout(() => { console.log('A') reject(new Error('AAAAAAAAAAA')) }, 5000) }), new Promise((resolve, reject) => { setTimeout(() => { console.log('B') reject(new Error('BBBBBBBBBBB')) }, 2000) }).catch(e => { return e }) ]).then(result => { console.log(result) }).catch(e => { console.log(e) }) } ---------------------------------------------- 控制檯前後輸出: B //2s後輸出B A //5s後輸出A AAAAAAAAAAA //A輸出後當即輸出錯誤'AAAAAAAAAAA'
上面代碼中爲何Promise. all最後捕獲的是錯誤'AAAAAAAAAAA'而不是‘BBBBBBBBBBB’。由於在第二個Promise實例中,2秒後雖然狀態變爲Rejected而且拋出了Error,可是被自身以後的catch方法捕獲了該錯誤且return。以前已經知道,Promise以後的then和catch方法其實返回的是一個新的Promise實例,若方法中沒有拋出新的錯誤,其後續的狀態就會變爲Resolved。而第一個實例拋出錯誤後,並未被後續方法捕獲,最後狀態爲Rejected,錯誤最終被外層Promise. all方法的後續catch所捕獲,最後輸出'AAAAAAAAAAA'。
與上面方法同樣,一樣將多個Promise實例包裝成一個新的Promise實例。
Promise.race([P1,P2,P3]) .then( value => { /*do something*/ } ) .catch(e => { /*do something*/ })
Promise實例組中,P一、P二、P3誰的狀態先發生變化(Resolved 或 Rejected),Promise.race()狀態也發生改變,P1(or P2 or P3)的返回值傳遞給Promise.race()回調函數。
將一個對象轉爲一個Promise對象,如下幾種狀況
①
let p = new Promise( (resolve,reject) => { resolve(1)} ) //傳入Promise對象p,返回仍是p Promise.resolve(p)
②
//傳入一個非thenable對象(thenable對象,就是一個對象具備then方法,下面會說明),或者非對象 Promise.resolve('_JayKoo') -------------------------------------- //上面代碼等同於 new Promise( (resolve,reject) =>{ resolve('_JayKoo'); })
③
//thenable對象,具備then方法的對象 //then方法知足如下格式 let obj = { then(res , rej){ //then函數,參數知足Promise回調函數中的參數格式。then函數,至關於,Promise構造函數中的回調函數格式。 if(/*Resolved*/){ res(value) } else { rej(error) } } } //將obj轉爲Promise對象,且當即調用then方法 Promise.resolve( obj ) --------------------------------------------------------------------------- //以上代碼的效果等同於當即執行了 new Promise( (res, rej) => { /*obj對象中的操做*/ if(/*Resolved*/){ res(value) } else { rej(error) } })
④
//不帶參數,當即生成一個Promise對象 //Promise.resolve()方法的執行,是在本輪註冊的全部同步腳本事件的結束時(非異步) let p = Promise.resolve()
Promise.reject()一樣返回Promise對象.。
在Promise.resolve()中,傳入的參數由thenable對象和非thenable對象兩種狀況,且以後的參數調用狀況也不一樣。
但在Promise.reject()中,全部傳參都會被當作Error拋出。
let p = Promise.reject(thenable) -------------------------------------- //等同於 let p = new Promise( (resolve,reject) => { //即便是個thenable對象,也會原封不動地將這個對象當作錯誤信息拋出 reject(thenable) }) -------------------------------------- p.catch( e => { console.log( e === thenable) }) //true