[譯]前端基礎知識儲備——Promise/A+規範

概述

自從準備晉級以後,就拖更了好久了,既然晉級弄完了,那麼也恢復更新了。javascript

在面試別人的過程當中,發現基本上沒有人對整個Promise徹底瞭解,所以但願經過這篇文章來幫助你們瞭解下Promise的全貌。本文的主要內容是Promise/A+規範的譯文,主要是可以幫助你們瞭解下Promise的規範,以及解決在平常運用中遇到的一些問題。java

原文地址爲:promisesaplus.com/#point-1git

若是須要測試一個Promise庫是否符合Promise/A+規範,可使用這個:github.com/promises-ap…github

原文概覽

一個標準聲明、可操做的JavaScript Promise——出自開發者,爲了開發者。面試

一個promise表明一個異步操做的最終結果。與promise交互的主要方法是經過它的then函數。這個函數註冊一個回調函數來接收promise最終的值(value)或者是沒有成功的緣由(reason)。promise

這篇文檔詳細說明了then方法的具體行爲,它爲全部的符合Promise/A+規範的實現提供了一個基礎的交互。像這樣,這個規範應該設計的很是穩定。儘管Promise/A+組織可能偶爾經過一些向後兼容的小修改來調整這個文檔來適應新發現的場景,咱們只會在經歷過了當心的思考、討論和測試後增長大的、不向後兼容的修改。異步

從歷史上來看,Promise/A+闡述了更早的Promise/A的行爲規範,而且在其基礎上進行了擴展,覆蓋了一些實際行爲和以前遺漏的問題。函數

最終,核心的Promise/A+文檔不關心如何去建立、完成(resolve)或者拒絕(reject)一個Promise,而是聚焦在提供一個可交互的then函數。在未來的其餘規範中可能會涉及這些沒有說起的內容。測試

1. 術語

1.1. "promise"是一個對象或者函數,它擁有一個符合文檔中描述行爲的then方法。this

1.2. "thenable"是一個有then方法的對象或者函數。

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狀態時,promise:

2.1.1.1. 可能會轉換成任何其餘的狀態。

2.1.2. 當處於fulfilled狀態時,promise:

2.1.2.1. 禁止轉換成其餘狀態。

2.1.2.2. 必須有一個沒法更改的值。

2.1.3. 當處於rejected狀態時,promise:

2.1.3.1. 禁止轉換成其餘狀態。

2.1.3.2. 必須有一個沒法更改的緣由。

在這裏,沒法更改意味着全等(例如===),可是不表明深比較相等。

2.2 then方法

promise必須包含一個then方法來訪問它當前或者最終的值或者緣由。

Promise的then方法接收兩個參數:

promise.then(onFulfilled, onRejected)
複製代碼

2.1.1. onFulfilledonRejected函數有都有可選的參數:

2.2.1.1. 若是onFulfilled不是一個函數,那麼它必須被忽略掉。

2.2.1.2. 若是onRejected不是一個函數,那麼它必須被忽略掉。

2.2.2. 若是onFulfilled是一個函數:

2.2.2.1. 它必須在promise到fulfilled狀態後觸發,promise的值是它的第一個參數。

2.2.2.2. 它在一個promise到fulfilled狀態以前禁止被觸發。

2.2.2.3. 它禁止被觸發屢次。

2.2.3. 若是onRejected是一個函數:

2.2.3.1. 它必須在promise到rejected狀態後觸發,promise的緣由是它的第一個參數。

2.3.2.2. 它在一個promise到rejected以前禁止被觸發。

2.3.2.3. 它禁止被觸發屢次。

2.2.4. onFulfilled或者onRejected只有在執行上下文堆棧只有平臺代碼時才能被觸發。

2.2.5. onFulfilledonRejected必須做爲函數被調用(例如沒有this值)。

2.2.6. then方法可能在相同的promise中被調用屢次。

2.2.6.1. 若是promise到了fullfilled狀態,那麼全部的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,那麼執行promise的解析過程[[Resolve]](promise2, x)

2.2.7.2. 若是onFulfilled或者onRejected方法拋出一個異常epromise2必須使用e做爲緣由拒絕掉(rejected)。

2.2.7.3. 若是onFulfilled不是一個函數而且promise1到了fulfilled狀態,那麼promise2必須在與promise1的值相同的狀況下轉換到fulfilled狀態。

2.2.7.4. 若是onRejected不是一個函數而且promise1到了rejected狀態,那麼promise2必須在與promise1的緣由相同的狀況下轉換到rejected狀態。

2.3. promise解析函數

promise解析函數是一個輸入一個promise或者一個值的抽象的操做,咱們表示爲[[Resolve]](promise, x)。若是x是一個thenable對象,在假定x的行爲至少有點像一個promise的狀況下,它會嘗試讓promise轉換到x的狀態。不然,他會用x的值完成promise的狀態。

這種thenable對象的方式容許promise實現交互,只要他們暴露一個符合Promise/A+規範的then函數。它還容許Promise/A+的實現支持一個有合適的then方法的不兼容的實現。

運行[[Resolve]](promise, x),須要遵循如下步驟:

2.3.1. 若是promisex指向同一個對象,那麼用TypeError做爲緣由拒絕promise。

2.3.2. 若是x是一個promise,判斷它的狀態:

2.3.2.1. 若是x是pending狀態,promise保留pending狀態直到x變成fulfilled狀態或者rejected狀態。

2.3.2.2. 若是x是fulfilled狀態,那麼用一樣的值將整個promise完成。

2.3.2.3. 若是x是rejected狀態,那麼用一樣的緣由拒絕promise

2.3.3. 不然,若是x是一個對象或者函數,

2.3.3.1. 讓then變成x.then

2.3.3.2. 若是在檢測x.then這個屬性的結果時拋出一個異常e,把e做爲緣由拒絕promise

2.3.3.3. 若是then是一個函數,那麼用x做爲this來調用它,第一個參數是resolvePromise,第二個參數是rejectPromise

2.3.3.3.1. 若是resolvePromise被值y調用,那麼運行[[Resolve]](promise, y)

2.3.3.3.2. 若是rejectPromise被緣由r觸發,那麼用r來拒絕promise

2.3.3.3.3. 若是resolvePromiserejectPromise都被調用,或者使用相同的參數屢次調用,那麼第一次調用生效,其餘以後的任何調用都忽略掉。

2.3.3.3.4. 若是在調用then方法時拋出了一個異常e,

2.3.3.3.4.1. 若是resolvePromiserejectPromise已經被調用了那麼就忽略掉它。

2.3.3.3.4.2. 不然,使用e做爲緣由拒絕promise

2.3.3.4. 若是then不是一個函數,那麼用x完成promise

2.3.4. 若是x不是一個對象或者函數,那麼用x完成promise

若是一個promise是經過在環形的thenable鏈中的一個thenable來完成的,如遞歸的[[Resolve]](promise, thenable)類型再次調用[[Resolve]](promise, thenable),遵循上述的規則會致使無窮遞歸。對這種遞歸狀況的檢測而且使用TypeError做爲緣由進行拒絕,咱們鼓勵實現,但不要求。

3. 注意事項

3.1. 在這裏"平臺代碼"(platform code)意味着引擎,環境和promise實現代碼。在實踐中,這個要求確保了onFulfilledonRejected是異步執行的,then調用也是在循環以後,有一個新的堆棧信息。這能夠經過一個宏任務(macro-task)機制例如setTimeout或者setImmediate來實現,也能夠經過一個微任務(micro-task)例如MutationObserver或者process.nextTick來實現。若是promise的實現考慮平臺代碼,那麼它本身可能會帶一個任務執行隊列或者「蹦牀」來處理被調用狀況。

3.2. 在嚴格模式下,this是在promise裏面將會是undefined。在鬆散模型下,他表明的是全局對象。

3.3. 若是實現知足全部要求的話,能夠容許promise2 === promise1。每個實現都應該代表是否支持promise2 === promise1,若是支持則是須要在什麼條件下。

3.4. 一般來講,若是按照當前的實現方式,咱們只能知道x是一個真的promise。這一條容許你在具體實現的使用過程當中來判斷未知的promise的狀態。

3.5. 在程序中,首先存儲x.then的引用,其次測試這個引用,而後再調用這個引用,避免屢次訪問x.then屬性。這樣的預防措施對於確保那些會在兩次訪問之間可能變化的屬性值獲取到一致的結果很是重要。

3.6. 實現中不該該對thenable調用鏈值設置任意深度限制,而是應該假設這個遞歸的限制值是無窮大。只有真正的循環纔會致使TypeError;若是遇到了一個長度爲無窮大的不一樣的thenable,保證在正確的行爲下一直遞歸。

總結

本文主要經過英文翻譯爲中文的Promise/A+規範,讓你們瞭解了整個規範的所有內容。我會在下一篇博客中給你們帶來如何實現一個徹底符合Promise/A+規範的Promise。

相關文章
相關標籤/搜索