原文連結
一個為健全可互操作的JavaScript Promise制定的開放标準。匠者為之,以惠匠者。
promise 表示一個異步操作的最終結果。與 promise 進行互動的主要方式是通過
then
方法,該方法注冊了兩個回調函數,用于接受 promise 的最終結果或者 promise 的據因。
本規範詳細列出了
then
方法的行為,所有遵循 Promises/A+ 規範實作的 promise 均可參照标準以實施
then
方法,故而提供了一個的可互操作的基礎。是以,本規範可以被認為是十分穩定的。盡管 Promises/A+ 組織可能有時會修訂本規範,造成微小的、向下相容的改變以解決新發現的一些邊界值,但我們僅僅在慎重考慮、詳細讨論和嚴格測試之後才會進行在大規模或向下不相容的內建。
從曆史上說, Promises/A+ 規範将之前 Promises/A 規範的建議明确為了行為标準。其擴充了原規範以覆寫一些約定俗成的行為,以及省略掉一些僅在特定情況下存在的或者有問題的部分。
最後,核心的 Promises/A+ 規範不設計如何建立、執行、拒絕 promises,而是專注于提供一個可互操作的
then
方法。上述對于 promises 的操作方法将來在其他規範中可能會觸及。
術語
- promise 是一個擁有
方法的對象或函數,其行為符合本規範。then
- thenable 是一個定義
方法的對象或函數。then
- 值(value) 指任何 JavaScript 的合法值(包括
, thenable 和 promise)。undefined
- 異常(exception) 是使用
語句抛出的一個值。throw
- 據因(reason) 是一個值以表明為何一個 promise 會被拒絕。
要求
Promise的狀态
一個 Promise 必須處于等待态(Pending)、執行态(Fulfilled)和拒絕态(Rejected)這三種狀态中的一種之中。
- 處于等待态時,promise :
- 可以遷移至執行态或拒絕态
- 處于執行态時,promise :
- 不能遷移至其他任何狀态
- 必須擁有一個不可變的值
- 處于拒絕态時,promise:
- 不能遷移至其他任何狀态
- 必須擁有一個不可變的據因
這裡的不可變指的是恒等(即可用
===
判斷相等),而不是意味着更深層次的不可變。
Then 方法
一個 promise 必須提供一個
then
方法以通路其目前值、最終傳回值和據因。
promise 的
then
方法接受兩個參數:
-
和onFulfilled
都是可選參數。onRejected
- 如果
不是函數,其必須被忽略onFulfilled
- 如果
不是函數,其必須被忽略onRejected
- 如果
- 如果
是函數:onFulfilled
- 當
執行結束後其必須被調用,其第一個參數為promise
的值promise
- 在
執行結束前其不可被調用promise
- 其調用次數不可超過一次
- 當
- 如果
是函數:onRejected
- 當
被拒絕執行後其必須被調用,其第一個參數為promise
的據因promise
- 在
被拒絕執行前其不可被調用promise
- 其調用次數不可超過一次
- 當
-
和onFulfilled
直到執行環境堆棧盡包含平台代碼前不可被調用 注1onRejected
-
和onFulfilled
必須被作為函數調用(即沒有onRejected
值)注2this
-
方法可以被同一個then
調用多次promise
- 當
成功執行時,所有promise
需按照其注冊順序依次回調onFulfilled
- 當
被拒絕執行時,所有的promise
需按照其注冊順序依次回調onRejected
- 當
-
方法必須傳回一個then
對象 注3promise
- 如果
或者onFulfilled
傳回一個值onRejected
,則運作下面的 Promise 解決程式:x
[[Resolve]](promise2, x)
- 如果
或者onFulfilled
抛出一個異常onRejected
,則e
必須拒絕執行,并傳回拒因promise2
e
- 如果
不是函數且onFulfilled
成功執行,promise1
必須成功執行并傳回相同的值promise2
- 如果
不是函數且onRejected
拒絕執行,promise1
必須拒絕執行并傳回相同的據因promise2
- 如果
Promise 解決程式
Promise解決程式是一個抽象的操作,其需輸入一個 promose 和一個值,我們表示為
[[Resolve]](promise, x)
,如果
x
是 thenable 的,同時若
x
至少滿足和
promise
類似(即鴨子類型,
x
擁有部分或全部
promise
擁有的方法屬性)的前提,解決程式即嘗試使
promise
接受
x
的狀态;否則其用
x
的值來執行
promise
。
這種對 thenable 的操作允許 promise 實作互操作,隻要其暴露出一個遵循 Promise/A+ 協定的
then
方法。
運作
[[Resolve]](promise, x)
需遵循以下步驟:
- 如果
和promise
指向同一對象,以x
為據因拒絕執行TypeError
promise
- 如果
為x
,接受其狀态 注4:promise
- 如果
處于等待态,x
需保持為等待态直至promise
被執行或拒絕x
- 如果
處于執行态,用相同的值執行x
promise
- 如果
處于拒絕态,用相同的據因拒絕x
promise
- 如果
- 抑或
為對象或者函數:x
- 設定
方法為then
注5x.then
- 如果取
的傳回值時抛出錯誤x.then
,則以e
為據因拒絕e
promise
- 如果
是函數,将then
作為函數的作用域x
調用之。其第一個參數為this
,第二個參數為resolvePromise
:rejectPromise
- 如果
以值resolvePromise
為參數被調用,則運作y
[[Resolve]](promise, y)
- 如果
以據因rejectPromise
為參數被調用,則以據因r
拒絕r
promise
- 如果
和resolvePromise
均被調用,或者被同一參數調用了多次,則優先采用首次調用和忽略剩下的調用rejectPromise
- 如果調用
方法抛出了異常then
:e
- 如果
或resolvePromise
已經被調用,則忽略之rejectPromise
- 否則以
為據因拒絕e
promise
- 如果
- 如果
不是函數,以then
為參數執行x
promise
- 如果
- 如果
不為對象或者函數,以x
為參數執行x
promise
- 設定
如果一個 promise 被一個循環的 thenable 鍊中的對象解決,而
[[Resolve]](promise, thenable)
的遞歸性質又使得其被再次調用,根據上述的算法将會陷入無限遞歸之中。算法不強制要求,但鼓勵其實施者以檢測這樣的遞歸是否存在,若存在則以一個可識别的
TypeError
為據因來拒絕
promise
注6。
注釋
- 注1 這裡的平台代碼指的是引擎、環境以及 promise 的實施代碼。實踐中要確定
和onFulfilled
在onRejected
方法被調用後的事件循環中異步執行和一個全新的堆棧。這可以用一個“宏任務”機制(如then
或setTimeout
)或者“微任務”機制(如setImmediate
或MutationObserver
)來實作。由于 promise 的實施代碼本身就是平台代碼,故其自身可以包含一個任務排程隊列或者在處理程式被調用時的“蹦床”。process.nextTick
- 注2 也就是說在嚴格模式(strict)中,函數
的值為this
;在非嚴格模式中其為全局對象。undefined
- 注3 代碼實作在滿足所有要求的情況下可以允許
。每個實作都要文檔說明其是否允許以及在何種條件下允許promise2 === promise1
。promise2 === promise1
- 注4 總體來說,其隻會知道
是真正的 promise 如果其來自目前實施。此标準允許使用特殊的實作方式以接受符合已知要求的 promises 狀态。x
- 注5 這一步是存儲一個指向
的引用,然後測試該引用,然後調用該引用。以避免多次通路x.then
屬性。這種預防措施在確定可通路屬性的一緻性上非常重要,因為其值可能在傳回時被改變。x.then
- 注6 實作不應該對 thenable 鍊的深度設限,并假定超出本限制的遞歸就是無限循環。隻有真正的循環遞歸才應能導緻
異常;如果一條無限長的鍊上 thenable 均不相同,那麼遞歸下去永遠是正确的行為。TypeError
此文為轉載,原文連結:http://www.ituring.com.cn/article/66566