自從準備晉級以後,就拖更了好久了,既然晉級弄完了,那麼也恢復更新了。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. "promise"是一個對象或者函數,它擁有一個符合文檔中描述行爲的then
方法。this
1.2. "thenable"是一個有then
方法的對象或者函數。
1.3. "value"是一個合法的JavaScript值(包括undefined
, 一個thenable或者一個promise)。
1.4. "exception"是一個使用在throw
語句中的拋出來的值。
1.5. "reason"是一個用來表示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. 必須有一個沒法更改的緣由。
在這裏,沒法更改意味着全等(例如===
),可是不表明深比較相等。
then
方法promise必須包含一個then
方法來訪問它當前或者最終的值或者緣由。
Promise的then
方法接收兩個參數:
promise.then(onFulfilled, onRejected)
複製代碼
2.1.1. onFulfilled
和onRejected
函數有都有可選的參數:
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. onFulfilled
和onRejected
必須做爲函數被調用(例如沒有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
方法拋出一個異常e
,promise2
必須使用e
做爲緣由拒絕掉(rejected)。
2.2.7.3. 若是onFulfilled
不是一個函數而且promise1
到了fulfilled狀態,那麼promise2
必須在與promise1
的值相同的狀況下轉換到fulfilled狀態。
2.2.7.4. 若是onRejected
不是一個函數而且promise1
到了rejected狀態,那麼promise2
必須在與promise1
的緣由相同的狀況下轉換到rejected狀態。
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. 若是promise
和x
指向同一個對象,那麼用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. 若是resolvePromise
和rejectPromise
都被調用,或者使用相同的參數屢次調用,那麼第一次調用生效,其餘以後的任何調用都忽略掉。
2.3.3.3.4. 若是在調用then
方法時拋出了一個異常e
,
2.3.3.3.4.1. 若是resolvePromise
和rejectPromise
已經被調用了那麼就忽略掉它。
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.1. 在這裏"平臺代碼"(platform code)意味着引擎,環境和promise實現代碼。在實踐中,這個要求確保了onFulfilled
和onRejected
是異步執行的,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。