寫在前面
注意單詞對應的翻譯,有助於理解整個模式
-
promise: 承諾
-
pending: 待定
-
settled: 定了
-
resolve(d): (已)解決
-
reject(ed): (已)拒絕
-
onFulfilled: 已履行(事件)
-
onRejected: 已拒絕(事件)
-
then: 然後,接下來
-
catch: 捕獲
-
race: 賽跑
-
future: 未來(值)
-
thenable:可 then 的(有 then 屬性的)
一.Promise 是什麼
一套異步操作處理機制,Promise A+ 是規範,jQuery、ES2015、q 的 promise 都是對該規範的一種實現
二.Promise 有什麼特點
-
更容易控制異步操作的執行順序
-
可以在一系列異步操作中,靈活地處理錯誤
-
支持鏈式調用,好寫
-
能夠消除回調金字塔,好看
三.Promise 有什麼用
-
實現串行任務隊列
-
實現串行任務管道
-
處理運行時才能確定執行順序的串行任務
(篇幅限制,具體適用場景以後再展開)
四.Promise 類型
內部屬性 [[PromiseStatus]]/[[PromiseValue]]
[[PromiseStatus]]:pending(待定) | resolved(已解決) | rejected(已拒絕)
後兩個統稱 settled(定了),pending 是初始狀態,如果 new Promise(func) 後,func 中的 resolve 和 reject 都還沒有執行,此時 status=pending
[[PromiseValue]]:undefined | resolve/reject 的參數 | Promise.resolve/reject 的!thenable 參數 | onFulfilled/onRejected 的返回值
當 then 被調用時,該值會被傳給 then 的 onFulfilled 或 onRejected,如果 resolve 和 reject 始終沒有執行,那麼 then 的 onFulfilled 和 onRejected 也始終不會執行
構造器參數 resolve/reject
resolve(解決)
執行 resolve 後,觸發 then 的 onFulfilled 回調,並把 resolve 的參數傳遞給 onFulfilled
reject(拒絕)
執行 reject 後,觸發 then | catch 的 onRejected 回調,並把 reject 的參數傳遞給 onRejected
注意:如果緊跟的 then 沒有聲明 onRejected 回調,則傳給下一個 then | catch 的 onRejected,還沒有,接著傳...如果走到頭都沒有,則報錯 Uncaught (in promise) Error:xxx
特殊的:如果 resolve 的參數是 Promise 對象,則該對象最終的 [[PromiseValue]] 會傳遞給外層 Promise 對象後續的 then 的 onFulfilled/onRejected,例如:
// 外層 then 能夠拿到內層 future 和 error
new Promise(function(resolve, reject) {
resolve(new Promise(function(resolve, reject) {
resolve(12);
// reject(new Error('reject in nested Promise'));
}).then(function(future) {
return future + 1;
}, function(error) {
return new Error('reject again in nested Promise');
}));
}).then(onFulfilled, onRejected);
// => 13 因為 onFulfilled 接收到了內層 promise 最終的 [[PromiseValue]]
// 如果是 reject,onFulfilled 將會接收到 Error('reject again')
五。基本語法
1.創建 Promise 對象
創建 Promise 的基本語法如下:
// 創建
var promise = new Promise(function(resolve, reject) {
if (/*...*/) {
resolve(data);
}
else {
reject(new Error('error occurs'));
}
});
// 使用
// then
promise.then(function(future) {
// ...
}, function(error) {
// ...
});
// catch
promise.catch(function(error) {
// ...
});
注意:new Promise(func) 時,func 會立即執行(不像 generator 只聲明不執行),執行過程中遇到 resolve() 裝沒看見(P.S.簡單理解為裝沒看見,解釋見註釋),遇到 reject() 立即拋出錯誤(注意:Chrome46 會立即拋出錯誤,FF39 不報錯,其它 polyfill,如 es6-promise、promise-polyfill 不報錯),對比例子如下:
new Promise(function(resolve, reject) {
console.log('#1');
resolve(1);
console.log('#2');
});
// => #1 #2 不報錯(遇到 resolve 裝沒看見)
// 其實內部屬性 [[PromiseStatus]] 和 [[PromiseValue]] 都變了,但沒有 then 提供的 onFulfilled 回調,看不到效果
new Promise(function(resolve, reject) {
console.log('#1');
reject(new Error('reject'));
console.log('#2');
});
// => #1 #2 Chrome46 報錯:Uncaught (in promise) Error: reject(…)
// 因為後面沒有 then/catch 提供的 onRejected 回調,異常沒有被消費掉
P.S.reject 的參數可以是任意類型的,但一般都傳入 Error 對象表示錯誤原因
2.Promise.prototype.then(onFulfilled, onRejected) 然後
給 promise 添加 onFulfilled/onRejected 回調 handler,當 promise 的 resolve/reject 執行時觸發對應 handler
注意:用 promise.then 添加回調函數時,如果 promise 已經處於 fulfilled 或 rejected 狀態,那麼相應的方法將會被立即調用
返回一個 Promise 對象(鏈式調用有戲),可以簡單理解為:
-
如果觸發了
onFulfilled,則該對象的 [[PromiseValue]]=onFulfilled 的返回值,[[PromiseStatus]]=resolvednew Promise(function(resolve, reject) { resolve(2); }).then(function(future) { return future * 2; }, onRejected).then(onFulfilled, onRejected); // onFulfilled 拿到了 4
-
如果觸發了 onRejected,則該對象的 [[PromiseValue]]=onRejected 的返回值,[[PromiseStatus]]=resolved
特別注意:返回對象的狀態是 resolved,而不是 rejected
new Promise(function(resolve, reject) {
reject(2);
}).then(null, function(err) {
return err * 2;
}).then(onFulfilled, onRejected);
// 還是 onFulfilled 拿到了 4,而不是 onRejected
P.S. 實際上 [[PromiseValue]]=undefined, [[PromiseStatus]]=pending,但仍將按照上述狀態來執行
3.Promise.prototype.catch(onRejected) 捕獲
等價於 then(null, onRejected),返回一個 Promise 對象,可以簡單理解為:
-
如果觸發了 onReject,則返回對象的 [[PromiseValue]]=onReject 的返回值,[[PromiseStatus]]=resolved
-
如果 onReject 始終沒有觸發,則裝作沒看見 catch,直接返回原 Promise 對象
var p = new Promise(function(resolve, reject) { resolve(2); }).catch(function() { console.log('onRejected'); return false; }); p.then(onFulfilled, onRejected); // onFulfilled 拿到了 2,catch 沒有任何影響
P.S. 實際上 [[PromiseValue]]=undefined, [[PromiseStatus]]=pending,但仍將按照上述狀態來執行
4.Promise.all(iterable)
返回 Promise 對象,當 iterable 中所有 promise 都 resolve 後,觸發 onFulfilled,遇到第一個否定 promise 就立即退出,並觸發 onRejected
//1.全肯定集合,觸發 onFulfilled,傳入的參數是集合中所有 promise 的 [[PromiseValue]] 組成的數組
Promise.all([getPromise(), getPromise()]).then(onFulfilled, onRejected);
//2.全否定集合,遇到第一個否定 promise 就退出,觸發 onRejected,傳入的參數是該 promise 的 [[PromiseValue]]
// Promise.all([getPromise(true), getPromise(true)]).then(onFulfilled, onRejected);
// 3.一般集合,同上
// Promise.all([getPromise(true), getPromise()]).then(onFulfilled, onRejected);
P.S.all,要麼全都正常完成,要麼因錯誤中斷,全都停下來
5.Promise.race(iterable) 賽跑
返回 Promise 對象,當 iterable 中有任意一個 promise 被 resolve 後就立即退出,並觸發 onFulfilled,遇到否定 promise 就立即退出,並觸發 onRejected
// 1.全肯定集合,遇到第一個肯定 promise 就退出,觸發 onFulfilled,傳入的參數是該 promise 的 [[PromiseValue]]
// Promise.race([getPromise(), getPromise()]).then(onFulfilled, onRejected);
// 2.全否定集合,遇到第一個否定 promise 就退出,觸發 onRejected,傳入的參數是該 promise 的 [[PromiseValue]]
// Promise.race([getPromise(true), getPromise(true)]).then(onFulfilled, onRejected);
// 3.一般集合,同上
// Promise.race([getPromise(true), getPromise()]).then(onFulfilled, onRejected);
P.S.「賽跑」,不論結果是肯定還是否定,只要最快的
6.Promise.resolve(value) 解決
-
如果
value是promise,則把promise中resolve/reject的參數傳遞給對應的onFulfilled/onRejectedPromise.resolve(getPromise()).then(onFulfilled, onRejected); // onFulfilled 拿到 resolve 的參數 Promise.resolve(getPromise(true)).then(onFulfilled, onRejected); // onRejected 拿到 reject 的參數
-
如果
value是 thenable 對象(有then屬性的對象),就會把obj包裝成 Promise 對象,該對象的then就是obj.thenPromise.resolve({ then: function(onFulfilled, onRejected) { // onFulfilled(1); onRejected(new Error('obj.then err'));
console.log('obj.then'); }}).then(onFulfilled, onRejected);
-
如果
value是!thenable 值,會把該值包裝成 Promise 對象,該對象的 [[PromiseValue]]=value, [[PromiseStatus]]=resolved,所以調用 then 方法時,onFulfilled 將會接收到這個值Promise.resolve(1).then(onFulfilled, onRejected); // onFulfilled 拿到 1
7.Promise.reject(reason) 拒絕
會把 reason 包裝成 Promise 對象,該對象的 [[PromiseValue]]=reason, [[PromiseStatus]]=rejected,所以調用 then 方法時,onRejected 將會接收到這個值
注意:這裡沒有 thenable/!thenable 的區別,一視同仁:
// 1.!thenable onRejected 將拿到 Error 對象
Promise.reject(new Error('static reject')).then(onFulfilled, onRejected);
// 2.promise onRejected 將拿到被包起來的肯定 Promise 對象
// 該對象的 [[PromiseValue]]=promise, [[PromiseStatus]]=rejected
Promise.reject(getPromise()).then(onFulfilled, onRejected);
// 3.thenable onRejected 將拿到{then: xxx}
Promise.reject({
then: function(onFulfilled, onRejected) {
console.log('obj.then');
}
}).then(onFulfilled, onRejected);
完整的測試 DEMO:promise 實例
六。高級用法
-
配合生成器(
generator) -
配合
async/await
(篇幅限制,以後再說)
暫無評論,快來發表你的看法吧