天天看點

js-Promise A+規範 術語 要求 注釋

原文連結

一個為健全可互操作的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 的合法值(包括 

    undefined

     , thenable 和 promise)。
  • 異常(exception) 是使用 

    throw

     語句抛出的一個值。
  • 據因(reason) 是一個值以表明為何一個 promise 會被拒絕。

要求

Promise的狀态

一個 Promise 必須處于等待态(Pending)、執行态(Fulfilled)和拒絕态(Rejected)這三種狀态中的一種之中。

  1. 處于等待态時,promise :
    • 可以遷移至執行态或拒絕态
  2. 處于執行态時,promise :
    • 不能遷移至其他任何狀态
    • 必須擁有一個不可變的值
  3. 處于拒絕态時,promise:
    • 不能遷移至其他任何狀态
    • 必須擁有一個不可變的據因

這裡的不可變指的是恒等(即可用 

===

 判斷相等),而不是意味着更深層次的不可變。

Then 方法

一個 promise 必須提供一個 

then

 方法以通路其目前值、最終傳回值和據因。

promise 的 

then

 方法接受兩個參數:

  1. onFulfilled

     和 

    onRejected

     都是可選參數。
    • 如果 

      onFulfilled

       不是函數,其必須被忽略
    • 如果 

      onRejected

       不是函數,其必須被忽略
  2. 如果 

    onFulfilled

     是函數:
    • 當 

      promise

       執行結束後其必須被調用,其第一個參數為 

      promise

       的值
    • 在 

      promise

       執行結束前其不可被調用
    • 其調用次數不可超過一次
  3. 如果 

    onRejected

     是函數:
    • 當 

      promise

       被拒絕執行後其必須被調用,其第一個參數為 

      promise

       的據因
    • 在 

      promise

       被拒絕執行前其不可被調用
    • 其調用次數不可超過一次
  4. onFulfilled

     和 

    onRejected

     直到執行環境堆棧盡包含平台代碼前不可被調用 注1
  5. onFulfilled

     和 

    onRejected

     必須被作為函數調用(即沒有 

    this

     值)注2
  6. then

     方法可以被同一個 

    promise

     調用多次
    • 當 

      promise

       成功執行時,所有 

      onFulfilled

       需按照其注冊順序依次回調
    • 當 

      promise

       被拒絕執行時,所有的 

      onRejected

       需按照其注冊順序依次回調
  7. then

     方法必須傳回一個 

    promise

     對象 注3
    • 如果 

      onFulfilled

       或者 

      onRejected

       傳回一個值 

      x

       ,則運作下面的 Promise 解決程式:

      [[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)

 需遵循以下步驟:

  1. 如果 

    promise

     和 

    x

     指向同一對象,以 

    TypeError

     為據因拒絕執行 

    promise

  2. 如果 

    x

     為 

    promise

     ,接受其狀态 注4:
    • 如果 

      x

       處于等待态, 

      promise

       需保持為等待态直至 

      x

       被執行或拒絕
    • 如果 

      x

       處于執行态,用相同的值執行 

      promise

    • 如果 

      x

       處于拒絕态,用相同的據因拒絕 

      promise

  3. 抑或 

    x

     為對象或者函數:
    • 設定 

      then

       方法為 

      x.then

       注5
    • 如果取 

      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

     或 

    process.nextTick

     )來實作。由于 promise 的實施代碼本身就是平台代碼,故其自身可以包含一個任務排程隊列或者在處理程式被調用時的“蹦床”。
  • 注2 也就是說在嚴格模式(strict)中,函數 

    this

     的值為 

    undefined

     ;在非嚴格模式中其為全局對象。
  • 注3 代碼實作在滿足所有要求的情況下可以允許 

    promise2 === promise1

     。每個實作都要文檔說明其是否允許以及在何種條件下允許 

    promise2 === promise1

     。
  • 注4 總體來說,其隻會知道 

    x

     是真正的 promise 如果其來自目前實施。此标準允許使用特殊的實作方式以接受符合已知要求的 promises 狀态。
  • 注5 這一步是存儲一個指向 

    x.then

     的引用,然後測試該引用,然後調用該引用。以避免多次通路 

    x.then

     屬性。這種預防措施在確定可通路屬性的一緻性上非常重要,因為其值可能在傳回時被改變。
  • 注6 實作不應該對 thenable 鍊的深度設限,并假定超出本限制的遞歸就是無限循環。隻有真正的循環遞歸才應能導緻 

    TypeError

     異常;如果一條無限長的鍊上 thenable 均不相同,那麼遞歸下去永遠是正确的行為。

此文為轉載,原文連結:http://www.ituring.com.cn/article/66566