ES6的Promise
相信凡是寫過javascript的童鞋也一定都寫過回調方法(callback),簡單說回調方法就是將一個方法func2作為參數傳入另一個方法func1中,當func1執行到某一步或者滿足某種條件的時候才執行傳入的參數func2,例如下面的代碼段
// 當參數a大於10且參數func2是一個方法時 執行func2
function func1(a, func2) {
if (a > 10 && typeof func2 == ‘function‘) {
func2()
}
}
func1(11, function() {
console.log(‘this is a callback‘)
})
一般來說我們會碰到的回調嵌套都不會很多,一般就一到兩級,但是某些情況下,回調嵌套很多時,代碼就會非常繁瑣,會給我們的編程帶來很多的麻煩,這種情況俗稱——回調地獄。極端情況如下圖:
badcallback.jpeg由此,Promise的概念就由社區提出並實現,作用與回調方法幾乎一致,都是在某種情況下執行預先設定好的方法,但是使用它卻能夠讓代碼變得更簡潔清晰
什麽是Promise
Promise是異步編程的一種解決方案,它有三種狀態,分別是pending-進行中、resolved-已完成、rejected-已失敗
當Promise的狀態又pending轉變為resolved或rejected時,會執行相應的方法,並且狀態一旦改變,就無法再次改變狀態,這也是它名字promise-承諾的由來
ES6之前的Promise
在ES6中,Promise終於成為了原生對象,可以直接使用。但是在這之前,小夥伴們想要使用Promise,一般會借助於第三方庫,或者當你知道其中的原理以後,也可以手動實現一個簡易的Promise
當然,為了防止不可預知的bug,在生產項目中最好還是不要使用原生的或者自己編寫的Promise(目前為止並不是所有瀏覽器都能很好的兼容ES6),而是使用已經較為成熟的有大量小夥伴使用的第三方Promise庫,下面就為小夥伴推薦一個—— Bluebird
Promise的基本用法
聲明一個Promise對象
// 方法1
let promise = new Promise ( (resolve, reject) => {
if ( success ) {
resolve(a) // pending ——> resolved 參數將傳遞給對應的回調方法
} else {
reject(err) // pending ——> rejectd
}
} )
// 方法2
function promise () {
return new Promise ( function (resolve, reject) {
if ( success ) {
resolve(a)
} else {
reject(err)
}
} )
}
註意:實例化的Promise對象會立即執行
Promise.prototype.then() VS Promise.prototype.catch()
.then()方法使Promise原型鏈上的方法,它包含兩個參數方法,分別是已成功resolved的回調和已失敗rejected的回調
promise.then(
() => { console.log(‘this is success callback‘) },
() => { console.log(‘this is fail callback‘) }
)
.catch()的作用是捕獲Promise的錯誤,與then()的rejected回調作用幾乎一致。但是由於Promise的拋錯具有冒泡性質,能夠不斷傳遞,這樣就能夠在下一個catch()中統一處理這些錯誤。同時catch()也能夠捕獲then()中拋出的錯誤,所以建議不要使用then()的rejected回調,而是統一使用catch()來處理錯誤
promise.then(
() => { console.log(‘this is success callback‘) }
).catch(
(err) => { console.log(err) }
)
同樣,catch()中也可以拋出錯誤,由於拋出的錯誤會在下一個catch中被捕獲處理,因此可以再添加catch()
使用rejects()方法改變狀態和拋出錯誤 throw new Error() 的作用是相同的
當狀態已經改變為resolved後,即使拋出錯誤,也不會觸發then()的錯誤回調或者catch()方法
then() 和 catch() 都會返回一個新的Promise對象,可以鏈式調用
promise.then(
() => { console.log(‘this is success callback‘) }
).catch(
(err) => { console.log(err) }
).then(
...
).catch(
...
)
Promise實例的異步方法和then()中返回promise有什麽區別?
// p1異步方法中返回p2
let p1 = new Promise ( (resolve, reject) => {
resolve(p2)
} )
let p2 = new Promise ( ... )
// then()中返回promise
let p3 = new Promise ( (resolve, reject) => {
resolve()
} )
let p4 = new Promise ( ... )
p3.then(
() => return p4
)
p1異步方法中返回p2
p1的狀態取決於p2,如果p2為pending,p1將等待p2狀態的改變,p2的狀態一旦改變,p1將會立即執行自己對應的回調,即then()中的方法針對的依然是p1
then()中返回promise
由於then()本身就會返回一個新的promise,所以後一個then()針對的永遠是一個新的promise,但是像上面代碼中我們自己手動返回p4,那麽我們就可以在返回的promise中再次通過 resolve() 和 reject() 來改變狀態
Promise的其他api
Promise.resolve() / Promise.reject()
用來包裝一個現有對象,將其轉變為Promise對象,但Promise.resolve()會根據參數情況返回不同的Promise:
參數是Promise:原樣返回
參數帶有then方法:轉換為Promise後立即執行then方法
參數不帶then方法、不是對象或沒有參數:返回resolved狀態的Promise
Promise.reject()會直接返回rejected狀態的Promise
Promise.all()
參數為Promise對象數組,如果有不是Promise的對象,將會先通過上面的Promise.resolve()方法轉換
var promise = Promise.all( [p1, p2, p3] )
promise.then(
...
).catch(
...
)
當p1、p2、p3的狀態都變成resolved時,promise才會變成resolved,並調用then()的已完成回調,但只要有一個變成rejected狀態,promise就會立刻變成rejected狀態
Promise.race()
var promise = Promise.race( [p1, p2, p3] )
promise.then(
...
).catch(
...
)
“競速”方法,參數與Promise.all()相同,不同的是,參數中的p1、p2、p3只要有一個改變狀態,promise就會立刻變成相同的狀態並執行對於的回調
Promise.done() / Promise. finally()
Promise.done() 的用法類似 .then() ,可以提供resolved和rejected方法,也可以不提供任何參數,它的主要作用是在回調鏈的尾端捕捉前面沒有被 .catch() 捕捉到的錯誤
Promise. finally() 接受一個方法作為參數,這個方法不管promise最終的狀態是怎樣,都一定會被執行
作者:君未來我已老
鏈接:https://www.jianshu.com/p/c98eb98bd00c
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請註明出處。
ES6的Promise