##一。介面分析
###1. 核心功能
- resolve(value)/reject(err)
建構函式引數 resolve/reject 雖然不是靜態方法也不是例項方法,卻是資料入口,所以是 promise API 的核心,promise 機制的大部分秘密都在裡面,所有公開介面都是在此基礎上工作的
- then(onFulfilled, onRejected)
除 resolve/reject 外,then 絕對是最重要的,其它所有例項方法/靜態方法都不是必要的,而 then 卻是必不可少的。換言之,能 new Promise 還支援 then,整個 promise 機制就完成了,其它介面都只是錦上添花的東西,讓 promise 變得更易用
###2. 例項方法
- catch(onRejected)
等價於 promise.then(null, onRejected),使用者可以少寫一點程式碼,同時賦予了語義(catch error)
###3. 靜態方法
- Promise.resolve(value)
提供一個 wrapper,不確定 value 是不是 Promise 例項時,可以用該方法獲取一個被包裝好的 Promise 例項,內部機制比較複雜,詳細資訊請參考 [6.Promise.resolve(value) 解決](/articles/完全理解 promise/#articleHeader14)
- Promise.reject(reason)
同樣提供一個 wrapper,是建立否定 Promise 的快捷方式,內部機制比 Promise.resolve(value) 簡單很多
- Promise.all(iterable)
要麼全都正常完成,要麼因錯誤中斷,未完成的全都停下來
- Promise.race(iterable)
「賽跑」,不論結果是肯定還是否定,只要最快的
###4. 高階功能
-
結果自動後拋
// 錯誤後拋 new Promise(function(resolve, reject) {reject('x')}) .then(null) .then(null) .catch(function(err) {console.log(err)}) // 值後拋 new Promise(function(resolve, reject) {resolve('x')}) .catch(null) .catch(null) .then(function(future) {console.log(future)})錯誤被拋給了最後的
catch,只要沒被「吃掉」就自動後拋,最後要麼被「吃掉」,要麼拋至頂層報錯 -
結果自動外拋
// 外層 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);外層的
then能夠拿到內層 future 和 error,避免手動維護狀態,也有利於錯誤集中處理
##二。難點
難點在於 promise 機制本身是非同步的,示例如下:
var p = new Promise(function(resolve, reject) {resolve(1)}).then(function(future) {return 2;});
// 立即輸出 p
console.log(p);
// 1s 後輸出 p
setTimeout(function() {
console.log(p);
}, 1000);
立即輸出的結果是:
// console
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
1s 後輸出的結果是:
// console
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2}
在這種非同步機制下,return 和 throw 都成了問題,例如:
// 非同步
function nextTick(fn) {
setTimeout(fn, 0);
}
// test
try {
nextTick(function() {
throw new Error('x');
});
}
catch (err) {
console.log('err: ' + err.message);
}
結果是無法 catch 錯誤,x 被拋到了頂層,顯示在控制檯了。很容易想到把 try..catch 放進去,嗯,錯誤確實 catch 住了,可是要如何通知外層?
return 和 throw ���是傳值的手段,在非同步環境下無法直接使用,需要我們自行實現一種傳值機制,這就是難點
P.S. 有一篇文章中提到了 try...catch 的缺點,詳細資訊請檢視 前端程式碼異常監控
##三。專案地址
地址:ayqy / myPromise - 程式碼託管 - 開源中國社群
注意:目前版本(v0.1.0 2015/12/13)存在很大問題,千萬不要直接使用,因為目前內部機制是同步的
P.S. 版本更新到可用時,筆者會在此處說明,在這之前,建議使用更靠譜的 taylorhakes/promise-polyfill · GitHub,很輕巧的實現
###參考資料
- [翻譯] We have a problem with promises:弄明白了 promise 的執行機制就不會出現這些問題,四種 promise 的區別也沒什麼好說的,但文中提到的錯誤值得注意
暫無評論,快來發表你的看法吧