- 原文地址:promisesaplus.com/
- Markdown 地址:github.com/Yangfan2016…
- 譯者:Yangfan2016
一個開放標準,對於開發人員可互操作的 JavaScript 承諾
一個 promise 代表一個非同步操作的最終結果。主要的操作方式是通過呼叫 promise 的 then
方法,它接受的回撥函式接受 promise 成功的結果或失敗的原因
這個規範詳細的描述了 then
方法的行為,提供一個互操作基礎,所有符合 Promises/A+ 的都可以依賴這個標準實現。因此,該規範已經十分穩定。儘管 Promises/A+ 組織可能會偶爾修改以實現向後相容,我們也會整合這些大的或不能向後相容的改變,一起研究,討論,測試。
曾經, Promises/A+ 解釋了早期 PromisesA 提議的條款,擴充套件了事實上的行為和忽略了不標準和有問題的部分。
最終,Promises/A+ 規範並沒處理如何建立 fulfill,或 reject promise,而選擇了可互操作的 then
方法替代。在今後的工作中可能會考慮。
1. 術語
1.1 ‘promise’ 是一個有符合此標準的 then
方法的 object
或 function
1.2 ‘thenable’ 是 then
方法定義的 object
或 function
1.3 ‘value’ 是一個 JavaScript 合法值(包括 undefined
,thenable,promise)
1.4 ‘exception’ 是一個 throw
語句丟擲錯誤的值
1.5 ‘reason’ 是一個表明 promise 失敗的原因的值
2. 要求
2.1 Promise 狀態
一個 promise 有且只有一個狀態(pending,fulfilled,rejected 其中之一)
2.1.1 pending 狀態時:
- 2.1.1.1 可能會轉變為 fulfilled 或 rejected 狀態
2.1.2 fulfilled 狀態時:
-
2.1.2.1 不能再狀態為任何其他狀態
-
2.1.2.2 必須有一個 value,且不可改變
2.1.3 rejected 狀態時:
-
2.1.3.1 不能再狀態為任何其他狀態
-
2.1.3.2 必須有一個 reason,且不可改變
注:這裡 ‘不可改變’ 意思是不可變恆等(同理 === ),但不意味永遠不可變
2.2 then 方法
一個 promise 必須提供一個 then
方法,用來獲取當前或最終的 value 或 reason
一個 promise 的 then
方法接受兩個引數:
promise.then(onFulfilled, onRejected)
2.2.1 onFulfilled 和 onRejected 都是可選引數:
-
2.2.1.1 如果 onFulfilled 不是函式,它會被忽略
-
2.2.1.2 如果 onRejected 不是函式,它會被忽略
2.2.2 如果 onFulfilled 是一個函式:
-
2.2.2.1 它一定是在 promise 是 fulfilled 狀態後呼叫,並且接受一個引數 value
-
2.2.2.2 它一定是在 promise 是 fulfilled 狀態後呼叫
-
2.2.2.3 它最多被呼叫一次
2.2.3 如果 onRejected 是一個函式:
-
2.2.3.1 它一定在 promise 是 rejected 狀態後呼叫,並且接受一個引數 reason
-
2.2.3.2 它一定在 promise 是 rejected 狀態後呼叫
-
2.2.3.3 它最多被呼叫一次
2.2.4 onFulfilled 或 onRejected 只在執行環境堆疊只包含平臺程式碼之後呼叫 [3.1]
2.2.5 onFulfilled 和 onRejected 會作為函式形式呼叫 (也就是說,預設 this
指向 global,嚴格模式 undefined
) [3.2]
2.2.6 在同一個 promise 例項中,then
可以鏈式呼叫多次
-
2.2.6.1 如果或當 promise 轉態是 fulfilled 時,所有的 onFulfilled 回撥回以他們註冊時的順序依次執行
-
2.2.6.2 如果或當 promise 轉態是 rejected 時,所有的 onRejected 回撥回以他們註冊時的順序依次執行
2.2.7 then 方法一定返回一個 promise
promise2 = promise1.then(onFulfilled, onRejected);
- 2.2.7.1 如果 onFulfilled 或 onRejected 返回的是一個 x,那麼它會以
[[Resolve]](promise2, x)
處理解析
-
2.2.7.2 如果 onFulfilled 或 onRejected 裡丟擲了一個異常,那麼 promise2 必須捕獲這個錯誤(接受一個 reason 引數)
-
2.2.7.3 如果 onFulfilled 不是一個函式,並且 promise1 狀態是 fulfilled,那麼 promise2 一定會接受到與 promse1 一樣的值 value
-
2.2.7.4 如果 onRejected 不是一個函式,並且 promise1 狀態是 rejected,promise2 一定會接受到與 promise1 一樣的值 reason
2.3 Promise 處理程式
promise 處理程式是一個表現形式為 [[Resolve]](promise, x) 的抽象處理操作。如果 x 是 thenable 型別,它會嘗試生成一個 promise 處理 x,否則它將直接 resolve x
只要 then 方法符合 Promises/A+ 規則,那麼對 thenables 處理就允許實現可互操作(鏈式呼叫,層層傳遞下去)。它也允許對那些不符合 Promises/A+ 的 then 方法進行 “吸收”
[[Resolve]](promise, x)
的執行表現形式如下步驟:
2.3.1 如果返回的 promise1 和 x 是指向同一個引用(迴圈引用),則丟擲錯誤
2.3.2 如果 x 是一個 promise 例項,則採用它的狀態:
-
2.3.2.1 如果 x 是 pending 狀態,那麼保留它(遞迴執行這個 promise 處理程式),直到 pending 狀態轉為 fulfilled 或 rejected 狀態
-
2.3.2.2 如果或當 x 狀態是 fulfilled,resolve 它,並且傳入和 promise1 一樣的值 value
-
2.3.2.3 如果或當 x 狀態是 rejected,reject 它,並且傳入和 promise1 一樣的值 reason
2.3.3 此外,如果 x 是個物件或函式型別
-
2.3.3.1 把
x.then
賦值給then
變數 -
2.3.3.2 如果捕獲(
try
,catch
)到x.then
丟擲的錯誤的話,需要 reject 這個promise -
2.3.3.3 如果
then
是函式型別,那個用 x 呼叫它(將then
的this
指向 x),第一個引數傳 resolvePromise ,第二個引數傳 rejectPromise:-
2.3.3.3.1 如果或當 resolvePromise 被呼叫並接受一個引數 y 時,執行
[[Resolve]](promise, y)
-
2.3.3.3.2 如果或當 rejectPromise 被呼叫並接受一個引數 r 時,執行 reject(r)
-
2.3.3.3.3 如果 resolvePromise 和 rejectPromise 已經被呼叫或以相同的引數多次呼叫的話嗎,優先第一次的呼叫,並且之後的呼叫全部被忽略(避免多次呼叫)
-
2.3.3.4 如果
then
執行過程中丟擲了異常,-
2.3.3.3.4.1 如果 resolvePromise 或 rejectPromise 已經被呼叫,那麼忽略異常
-
2.3.3.3.4.2 否則,則 reject 這個異常
-
-
-
2.3.3.4 如果
then
不是函式型別,直接 resolve x(resolve(x))
2.3.4 如果 x 即不是函式型別也不是物件型別,直接 resolve x(resolve(x))
如果被 resolve 的 promise 參與了 thenable 的迴圈鏈中,那麼可能會導致無限遞迴。我們鼓勵實現檢測這種無限遞迴的方法並且返回一個錯誤資訊,但並不是必須的 [3.6]
3. 備註
3.1 這裡的 “平臺程式碼”是指引擎,環境,和 promise 實現程式碼。實際上,這個要求確保 onFulfilled 和 onRejected 都在下一輪的事件迴圈中(一個新的棧)被非同步呼叫。可以用巨集任務,例如:setTimeout
,setImmediate
或者微任務,例如:MutationObsever
或 process.nextTick
實現。 由於 promise 的實現被當做平臺程式碼,所以它本身可能包含一個任務佇列或 “trampoline” 的處理程式
3.2 這個 this
在嚴格模式下是 undefined
,在寬鬆模式,指向 global 物件
3.3 具體的實現可以允許 promise2 和 promise1 絕對相等,要滿足所有要求。每一個處理 promise2 和 promise1 絕對相等的實現都要寫上文件標註
3.4 通常,只有它來自當前實現才可以判斷 x 是一個真正的 promise。 此條款允許採取已知符合 promise 標準實現的狀態
3.5 把 x.then
存起來,然後測試、呼叫這個引用,避免多次訪問 x.then
屬性。這麼做的原因是防止每次獲取 x.then
時,返回不同的情況(ES5
的 getter
特性可能會產生副作用)
3.6 實現不應該武斷地限制 thenable 鏈的深度,假設超出限制的無限遞迴。只有真正的迴圈引用才會導致一個 TypeError
錯誤,如果遇到一個不同的無限遞迴 thenable 鏈,一直遞迴永遠是正確的行為
- 本文僅代表原作者個人觀點,譯者不發表任何觀點
- Markdown 檔案由譯者手動整理,如有勘誤,歡迎指正
- 譯文和原文采用一樣協議,侵刪