接觸Promise很久了,但一直也沒用過,感覺很陌生,但是ES2015來了,是時(shí)候使用了,本文將介紹Promise的方方面面,同時(shí)也是自己學(xué)習(xí)的過程。
本文將會(huì)盡可能使用ES2015的語法,這可能需要你使用一款現(xiàn)代瀏覽器,如果你還不了解可以閱讀下這篇文章。
Promise的瀏覽器兼容性如下,你需要選一款兼容的瀏覽器才可以,你也可以點(diǎn)擊這里查看。
Promise其實(shí)是Node社區(qū)中誕生的產(chǎn)物,如果你寫過Node你肯定會(huì)知道為了異步,寫了那么多的回調(diào),而Promise就是比回調(diào)更有好的方式。
所謂Promise,就是一個(gè)對(duì)象,用來傳遞異步操作的消息。它代表了某個(gè)未來才會(huì)知道結(jié)果的事件(通常是一個(gè)異步操作),并且這個(gè)事件提供統(tǒng)一的API,可供進(jìn)一步處理。
如果你有興趣可以閱讀一下Promise的規(guī)范,但我不太感興趣,我將從實(shí)踐的角度來學(xué)習(xí)它。
Promise是一個(gè)構(gòu)造函數(shù)(類),可以使用new運(yùn)算符新建一個(gè)實(shí)例,然后就可以使用了,構(gòu)造函數(shù)接受一個(gè)函數(shù)作為參數(shù)。
var p = new Promise((resolve, reject) => {
window.setTimeout(() => {resolve(123);}, 1000);
});
p.then((data) => {
console.log('p success', data);
});
上面的代碼輸出如下:
=> p success 123
新建Promise對(duì)象時(shí)傳入的函數(shù),接受兩個(gè)參數(shù),resolve和reject,分別用來改變Promise的狀態(tài),創(chuàng)建好,調(diào)用resolve和reject時(shí),可以傳入?yún)?shù),這個(gè)參數(shù)會(huì)自動(dòng)傳遞個(gè)后面的回調(diào)函數(shù)中。
創(chuàng)建好promise后,可以通過then方法定制狀態(tài)變化后的回調(diào)函數(shù)。
好了這就是使用Promise的全部代碼了,剩下的部分就全靠你的發(fā)揮了,下面將會(huì)介紹常用的API。
打開瀏覽器的控制臺(tái),輸入如下代碼:
Object.getOwnPropertyNames(Promise.prototype).sort().forEach(function (val) {console.log(val, '\n')});
在我的瀏覽器中上面的代碼會(huì)有如下輸出,可能不同瀏覽器會(huì)不一樣。
這里我們將重點(diǎn)關(guān)注如下接口:
catch() 方法只處理Promise被拒絕的情況,并返回一個(gè)Promise。該方法的行為和調(diào)用Promise.prototype.then(undefined, onRejected)相同。
p.catch((reason) => {
// 拒絕
});
更多信息,請(qǐng)點(diǎn)擊這里查看。
then()方法返回一個(gè)Promise。它有兩個(gè)參數(shù),分別為Promise在 success 和 failure 情況下的回調(diào)函數(shù)。
p.then((value) => {
// 滿足
}, (reason) => {
// 拒絕
});
更多信息,請(qǐng)點(diǎn)擊這里查看。
我們也先來看看瀏覽器支持哪些接口,在控制臺(tái)輸入如下代碼:
Object.getOwnPropertyNames(Promise).sort().forEach(function (val) {console.log(val, '\n')});
會(huì)看到如下的輸出:
我們將重點(diǎn)關(guān)注一下屬性:
Promise.all(iterable) 方法返回一個(gè)promise,該promise會(huì)在iterable參數(shù)內(nèi)的所有promise都被解決后被解決。
Promise.all(iterable);
iterable是一個(gè)可迭代對(duì)象,比如Array。
更多信息,請(qǐng)點(diǎn)擊這里查看。
Promise.race(iterable)方法返回一個(gè)promise,這個(gè)promise在iterable中的任意一個(gè)promise被解決或拒絕后,立刻以相同的解決值被解決或以相同的拒絕原因被拒絕。
Promise.race(iterable);
iterable是一個(gè)可迭代對(duì)象,比如Array。
更多信息,請(qǐng)點(diǎn)擊這里查看。
Promise.reject(reason)方法返回一個(gè)用reason拒絕的Promise。
Promise.reject(reason);
reason Promise被拒絕的原因。
更多信息,請(qǐng)點(diǎn)擊這里查看。
Promise.resolve(value)方法返回一個(gè)以給定值resolve掉的Promise對(duì)象。但如果這個(gè)值是thenable的(就是說帶有then方法),返回的promise會(huì)“追隨”這個(gè)thenable的對(duì)象,接收它的最終狀態(tài)(指resolved/rejected/pendding/settled);否則這個(gè)被返回的promise對(duì)象會(huì)以這個(gè)值被fulfilled。
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
value 用來resolve待返回的promise對(duì)象的參數(shù)。既可以是一個(gè)Promise對(duì)象也可以是一個(gè)thenable。
更多信息,請(qǐng)點(diǎn)擊這里查看。
我們構(gòu)造一段下面的代碼,基本上用到了上面的全部知識(shí):
// 1000ms 后success
var p1 = new Promise((resolve, reject) => {
window.setTimeout(() => {resolve(123);}, 1000);
});
p1.then((data) => {
console.log('p1 success', data);
});
// 2000ms 后success
var p2 = new Promise((resolve, reject) => {
window.setTimeout(() => {resolve(456);}, 2000);
});
p2.then((data) => {
console.log('p2 success', data);
});
var pa = Promise.all([p1, p2]);
var pr = Promise.race([p1, p2]);
pa.then((data) => {
console.log('pa success', data);
});
pr.then((data) => {
console.log('pr success', data);
});
上面的代碼輸出如下:
// 1000ms
p1 success 123
pr success 123
// 2000ms
p2 success 456
pa success [123, 456]
如果要兼容舊的瀏覽器,又要使用新特性,那么只能使用Polyfill了,類似的庫很多,我推薦使用es6-promise
es6-promise是一個(gè)兼容 ES6 Promises 的Polyfill類庫。 它基于 RSVP.js 這個(gè)兼容 Promises/A+ 的類庫, 它只是 RSVP.js 的一個(gè)子集,只實(shí)現(xiàn)了Promises 規(guī)定的 API。
關(guān)于使用方法和注意事項(xiàng)這個(gè)庫的文檔都寫得很詳細(xì)了,在此不再詳細(xì)介紹了。
是時(shí)候使用Promise了,上面已經(jīng)介紹了ES2015 Promise的全部內(nèi)容了,如果你還想閱讀更多資料,可查看下面的參考資料,如果你有任何疑問或建議,歡迎在下面的評(píng)論區(qū)和我討論。
更多建議: