promise A+規(guī)范翻譯 2021-04-12

原文

An open standard for sound, interoperable JavaScript promises—by implementers, for implementers.

A promise represents the eventual result of an asynchronous operation. The primary way of interacting with a promise is through its then method, which registers callbacks to receive either a promise’s eventual value or the reason why the promise cannot be fulfilled.

This specification details the behavior of the then method, providing an interoperable base which all Promises/A+ conformant promise implementations can be depended on to provide. As such, the specification should be considered very stable. Although the Promises/A+ organization may occasionally revise this specification with minor backward-compatible changes to address newly-discovered corner cases, we will integrate large or backward-incompatible changes only after careful consideration, discussion, and testing.

Historically, Promises/A+ clarifies the behavioral clauses of the earlier Promises/A proposal, extending it to cover de facto behaviors and omitting parts that are underspecified or problematic.

Finally, the core Promises/A+ specification does not deal with how to create, fulfill, or reject promises, choosing instead to focus on providing an interoperable then method. Future work in companion specifications may touch on these subjects.

Terminology

  1. “promise” is an object or function with a then method whose behavior conforms to this specification.
  2. “thenable” is an object or function that defines a then method.
  3. “value” is any legal JavaScript value (including undefined, a thenable, or a promise).
  4. “exception” is a value that is thrown using the throw statement.
  5. “reason” is a value that indicates why a promise was rejected.

Requirements

Promise States

A promise must be in one of three states: pending, fulfilled, or rejected.

  1. When pending, a promise:
    1. may transition to either the fulfilled or rejected state.
  2. When fulfilled, a promise:
    1. must not transition to any other state.
    2. must have a value, which must not change.
  3. When rejected, a promise:
    1. must not transition to any other state.
    2. must have a reason, which must not change.

Here, “must not change” means immutable identity (i.e. ===), but does not imply deep immutability.

The then Method

A promise must provide a then method to access its current or eventual value or reason.

A promise’s then method accepts two arguments:

promise.then(onFulfilled, onRejected)

  1. Both onFulfilled and onRejected are optional arguments:

    1. If onFulfilled is not a function, it must be ignored.
    2. If onRejected is not a function, it must be ignored.
  2. If onFulfilled is a function:

    1. it must be called after promise is fulfilled, with promise’s value as its first argument.
    2. it must not be called before promise is fulfilled.
    3. it must not be called more than once.
  3. If onRejected is a function,

    1. it must be called after promise is rejected, with promise’s reason as its first argument.
    2. it must not be called before promise is rejected.
    3. it must not be called more than once.
  4. onFulfilled or onRejected must not be called until the execution context stack contains only platform code. [3.1].

  5. onFulfilled and onRejected must be called as functions (i.e. with no this value). [3.2]

  6. then may be called multiple times on the same promise.

    1. If/when promise is fulfilled, all respective onFulfilled callbacks must execute in the order of their originating calls to then.
    2. If/when promise is rejected, all respective onRejected callbacks must execute in the order of their originating calls to then.
  7. then must return a promise [3.3].

     promise2 = promise1.then(onFulfilled, onRejected);
    
    
    1. If either onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x).
    2. If either onFulfilled or onRejected throws an exception e, promise2 must be rejected with e as the reason.
    3. If onFulfilled is not a function and promise1 is fulfilled, promise2 must be fulfilled with the same value as promise1.
    4. If onRejected is not a function and promise1 is rejected, promise2 must be rejected with the same reason as promise1.

The Promise Resolution Procedure

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x.

This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.

To run [[Resolve]](promise, x), perform the following steps:

  1. If promise and x refer to the same object, reject promise with a TypeError as the reason.
  2. If x is a promise, adopt its state [3.4]:
    1. If x is pending, promise must remain pending until x is fulfilled or rejected.
    2. If/when x is fulfilled, fulfill promise with the same value.
    3. If/when x is rejected, reject promise with the same reason.
  3. Otherwise, if x is an object or function,
    1. Let then be x.then. [3.5]
    2. If retrieving the property x.then results in a thrown exception e, reject promise with e as the reason.
    3. If then is a function, call it with x as this, first argument resolvePromise, and second argument rejectPromise, where:
      1. If/when resolvePromise is called with a value y, run [[Resolve]](promise, y).
      2. If/when rejectPromise is called with a reason r, reject promise with r.
      3. If both resolvePromise and rejectPromise are called, or multiple calls to the same argument are made, the first call takes precedence, and any further calls are ignored.
      4. If calling then throws an exception e,
        1. If resolvePromise or rejectPromise have been called, ignore it.
        2. Otherwise, reject promise with e as the reason.
    4. If then is not a function, fulfill promise with x.
  4. If x is not an object or function, fulfill promise with x.

If a promise is resolved with a thenable that participates in a circular thenable chain, such that the recursive nature of [[Resolve]](promise, thenable) eventually causes [[Resolve]](promise, thenable) to be called again, following the above algorithm will lead to infinite recursion. Implementations are encouraged, but not required, to detect such recursion and reject promise with an informative TypeError as the reason. [3.6]

Notes

  1. Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

  2. That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.

  3. Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions.

  4. Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.

  5. This procedure of first storing a reference to x.then, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals.

  6. Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.

中文譯文

由開發(fā)者制定的開放、通用可信任的的promise標(biāo)準(zhǔn),供開發(fā)者參考

promise代表了一個異步操作的最終結(jié)果。promise最主要的交互方式是通過它的 then方法卓囚,這個方法注冊了回調(diào)函數(shù)用來接受一個promise的最終value或者被reject的reason。

該規(guī)范詳細說明了then方法的行為,為所有符合promise/A+規(guī)范實現(xiàn)的promise均可以本標(biāo)準(zhǔn)作為參照基礎(chǔ)來實施 then 方法艘虎。因為這個規(guī)則十分穩(wěn)定。盡管Promises / A +組織有時會通過向后兼容的微小更改來修訂此規(guī)范,以解決新發(fā)現(xiàn)的極端情況蔑水,但只有在仔細考慮,討論和測試之后扬蕊,我們才會集成大型或向后不兼容的更改搀别。

從歷史上看,Promises / A +闡明了較早Promises / A提案的行為條款尾抑,將其擴展為涵蓋事實上的行為歇父,并省略了未指定或有問題的部分蒂培。


最后,核心的Promises / A +規(guī)范不涉及如何create庶骄,fulfill或reject一個promise毁渗,而是選擇專注于提供可互操作的then方法。 規(guī)范中的未來工作可能涉及這些主題单刁。

術(shù)語

  1. "promise"是一個對象或函數(shù),它擁有符合此規(guī)范的then方法

  2. "thenable"是一個對象或者方法府适,它定義了一個then方法羔飞。

  3. "value"是一個任意合法javascript值(可以是'undefined',thenable或promise)

  4. "exception"是通過throw聲明拋出的一個錯誤

  5. "reason"表明了一個promise失敗的原因。

要求

Promise 狀態(tài)

一個promise 必須處于以下三個狀態(tài)種的一種: pending檐春,fulfilled或rejecged

  1. 在pending狀態(tài)時逻淌,promise:
    1. 可以轉(zhuǎn)變?yōu)閒ulfilled或rejected狀態(tài)。
  2. 當(dāng)fulfilled狀態(tài)時, a promise:
    1. 無法轉(zhuǎn)換到其他狀態(tài)疟暖。
    2. 一定會包含一個value卡儒,并且無法改變
  3. 當(dāng)rejected狀態(tài)時,promise:
    1. 不能轉(zhuǎn)換到其他狀態(tài)
    2. 必定有reason俐巴,并且無法改變

在這里骨望,“不能轉(zhuǎn)換”意味著恒等(可以用===判斷),但不適用于深層的改變(如果value或reason不為基本類型欣舵,可能會修改屬性值)擎鸠。

then方法

promise必須提供一個then方法來訪問它的當(dāng)前值或最終value/reason。

promise的then方法接收2個參數(shù)值:

promise.then(onFulfilled, onRejected)

  1. onFulfilledonRejected都是可選參數(shù):

    1. onFulfilled 如果不為函數(shù)缘圈,則會被忽略執(zhí)行
    2. onRejected如果不為函數(shù)劣光,則會被忽略執(zhí)行
  2. onFulfilled如果是函數(shù):

    1. 在promise變?yōu)閒ulfilled之后才會被調(diào)用,promise的value會時它的第一個參數(shù)值糟把。
    2. 在promise變成fulfilled之前都不會被調(diào)用绢涡。
    3. 不能被調(diào)用超過一次。
  3. onRejected如果是一個函數(shù)

    1. 一定會在promise狀態(tài)變成rejected之后調(diào)用遣疯,promise的reason是它第一個參數(shù)雄可。
    2. 在promise狀態(tài)沒有變?yōu)閞ejected之前不會被調(diào)用。
    3. [](https://promisesaplus.com/#point-33)無法被調(diào)用超過一次另锋。
  4. onFulfilledonRejected 只有在執(zhí)行環(huán)境堆棧僅包含平臺代碼時才可被調(diào)用
    [3.1].

  5. onFulfilledonRejected 必須被用作函數(shù)調(diào)用 (i.e. with no this value). [3.2]

  6. then 允許在一個promise中調(diào)用多次

    1. 當(dāng)promise狀態(tài)變?yōu)閒ulfilled滞项,所有onFullfilled回調(diào)必須按照初始調(diào)用then方法的先后順序執(zhí)行。
    2. 當(dāng)promise狀態(tài)變?yōu)閞ejected夭坪,所有onRejected回調(diào)必須按照初始調(diào)用then方法的先后順序執(zhí)行文判。
  7. then 方法必定返回一個promise [3.3].

     promise2 = promise1.then(onFulfilled, onRejected);
    
    
    1. 如果 onFulfilled 或者 onRejected 返回一個值 x ,則運行下面的 Promise 解決過程:[[Resolve]](promise2, x)
  8. 如果onFulfilledonRejected拋出一個一場 e, promise2必定返回e作為一reason室梅。

  9. 如果onFulfilled不是一個函數(shù)并且 promise1是fulfilled狀態(tài)戏仓, promise2 必定和promise1有同樣的value疚宇。

  10. 如果onRejected不是一個函數(shù)并且 promise1 處于rejected狀態(tài), promise2promise1有相同的rason值

Promise解決過程

promise 解決過程是一個抽象操作,它輸入一個promise和一個value赏殃,我們可以表示為 [[Resolve]](promise, x). 如果 x 有 then 方法且看上去像一個 Promise 敷待,解決程序即嘗試使 promise 接受 x 的狀態(tài);否則其用 x 的值來執(zhí)行 promise 仁热。

這種 thenable 的特性使得 Promise 的實現(xiàn)更具有通用性:只要其暴露出一個遵循 Promise/A+ 協(xié)議的 then 方法即可榜揖;這同時也使遵循 Promise/A+ 規(guī)范的實現(xiàn)可以與那些不太規(guī)范但可用的實現(xiàn)能良好共存。

運行 [[Resolve]](promise, x) 需遵循以下步驟

  1. 如果promisex指向同一個對象抗蠢,使用TypeError來將promise該為rejected举哟。
  2. 如果 x 為 Promise ,則使 promise 接受 x 的狀態(tài) [3.4]:
    1. 如果 x 處于pending迅矛, promise 需保持為等待態(tài)直至 x 被執(zhí)行或拒絕
    2. 如果 x 處于fulfiiled妨猩,用相同的值執(zhí)行 promise
    3. 如果 x 處于rejected,用相同的值拒絕 promise
  3. 如果x是一個對象或函數(shù)
    1. 把 x.then 賦值給 then [3.5]
    2. 如果取 x.then 的值時拋出錯誤 e 秽褒,則以 e 為據(jù)因拒絕 promise
    3. 果 then 是函數(shù)壶硅,將 x 作為函數(shù)的作用域 this 調(diào)用之。傳遞兩個回調(diào)函數(shù)作為參數(shù)销斟,第一個參數(shù)叫做 resolvePromise 庐椒,第二個參數(shù)叫做 rejectPromise:
      1. 如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運行 [[Resolve]](promise, y)
      2. 如果 rejectPromise 以據(jù)因 r 為參數(shù)被調(diào)用票堵,則以據(jù)因 r 拒絕 promise
      3. 如果 resolvePromise 和 rejectPromise 均被調(diào)用扼睬,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用
      4. 如果調(diào)用 then 方法拋出了異常 e:
        1. I如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用悴势,則忽略之
        2. 否則以 e 為據(jù)因拒絕 promise
    4. 如果 then 不是函數(shù)窗宇,以 x 為參數(shù)執(zhí)行 promise
  4. 如果 x 不為對象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise

如果一個 promise 被一個循環(huán)的 thenable 鏈中的對象解決特纤,而 [[Resolve]](promise, thenable) 的遞歸性質(zhì)又使得其被再次調(diào)用军俊,根據(jù)上述的算法將會陷入無限遞歸之中。算法雖不強制要求捧存,但也鼓勵施者檢測這樣的遞歸是否存在粪躬,若檢測到存在則以一個可識別的 TypeError 為據(jù)因來拒絕 promise[3.6]

Notes

  1. Here “platform code” means engine, environment, and promise implementation code. In practice, this requirement ensures that onFulfilled and onRejected execute asynchronously, after the event loop turn in which then is called, and with a fresh stack. This can be implemented with either a “macro-task” mechanism such as setTimeout or setImmediate, or with a “micro-task” mechanism such as MutationObserver or process.nextTick. Since the promise implementation is considered platform code, it may itself contain a task-scheduling queue or “trampoline” in which the handlers are called.

  2. That is, in strict mode this will be undefined inside of them; in sloppy mode, it will be the global object.

  3. Implementations may allow promise2 === promise1, provided the implementation meets all requirements. Each implementation should document whether it can produce promise2 === promise1 and under what conditions.

  4. Generally, it will only be known that x is a true promise if it comes from the current implementation. This clause allows the use of implementation-specific means to adopt the state of known-conformant promises.

  5. This procedure of first storing a reference to x.then, then testing that reference, and then calling that reference, avoids multiple accesses to the x.then property. Such precautions are important for ensuring consistency in the face of an accessor property, whose value could change between retrievals.

  6. Implementations should not set arbitrary limits on the depth of thenable chains, and assume that beyond that arbitrary limit the recursion will be infinite. Only true cycles should lead to a TypeError; if an infinite chain of distinct thenables is encountered, recursing forever is the correct behavior.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市昔穴,隨后出現(xiàn)的幾起案子镰官,更是在濱河造成了極大的恐慌,老刑警劉巖吗货,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泳唠,死亡現(xiàn)場離奇詭異,居然都是意外死亡宙搬,警方通過查閱死者的電腦和手機笨腥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門拓哺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脖母,你說我怎么就攤上這事士鸥。” “怎么了谆级?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵烤礁,是天一觀的道長。 經(jīng)常有香客問我肥照,道長鸽凶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任建峭,我火速辦了婚禮,結(jié)果婚禮上决摧,老公的妹妹穿的比我還像新娘亿蒸。我一直安慰自己,他們只是感情好掌桩,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布边锁。 她就那樣靜靜地躺著,像睡著了一般波岛。 火紅的嫁衣襯著肌膚如雪茅坛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天则拷,我揣著相機與錄音贡蓖,去河邊找鬼。 笑死煌茬,一個胖子當(dāng)著我的面吹牛斥铺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播坛善,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼晾蜘,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了眠屎?” 一聲冷哼從身側(cè)響起剔交,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎改衩,沒想到半個月后岖常,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡燎字,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年腥椒,在試婚紗的時候發(fā)現(xiàn)自己被綠了阿宅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡笼蛛,死狀恐怖洒放,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滨砍,我是刑警寧澤往湿,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站惋戏,受9級特大地震影響领追,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜响逢,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一绒窑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧舔亭,春花似錦些膨、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矛洞,卻和暖如春洼哎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沼本。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工噩峦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擅威。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓壕探,卻偏偏與公主長得像,于是被迫代替她去往敵國和親郊丛。 傳聞我的和親對象是個殘疾皇子李请,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容