http://www.cnblogs.com/lvdabao/p/5320705.html @呂大豹 html
promise 是一個擁有 then
方法的對象或函數,其行爲符合本規範;前端
是一個定義了 then
方法的對象或函數,文中譯做「擁有 then
方法」;jquery
指任何 JavaScript 的合法值(包括 undefined
, thenable 和 promise);git
是使用 throw
語句拋出的一個值。github
表示一個 promise 的拒絕緣由。面試
處於等待態時,promise 需知足如下條件:算法
處於拒絕態時,promise 需知足如下條件:promise
這裏的不可變指的是恆等(便可用 ===
判斷相等),而不是意味着更深層次的不可變(譯者注: 蓋指當 value 或 reason 不是基本值時,只要求其引用地址相等,但屬性值可被更改)。瀏覽器
一個 promise 必須提供一個 then
方法以訪問其當前值、終值和據因。前端工程師
then
方法接受兩個參數:
onFulfilled
和 onRejected
都是可選參數。
onFulfilled
不是函數,其必須被忽略onRejected
不是函數,其必須被忽略onFulfilled
特性若是 onFulfilled
是函數:
promise
執行結束後其必須被調用,其第一個參數爲 promise
的終值promise
執行結束前其不可被調用onRejected
特性若是 onRejected
是函數:
promise
被拒絕執行後其必須被調用,其第一個參數爲 promise
的據因promise
被拒絕執行前其不可被調用onFulfilled
和 onRejected
只有在執行環境堆棧僅包含平臺代碼時纔可被調用 注1
then
方法能夠被同一個 promise
調用屢次
promise
成功執行時,全部 onFulfilled
需按照其註冊順序依次回調promise
被拒絕執行時,全部的 onRejected
需按照其註冊順序依次回調onFulfilled
或者
onRejected
返回一個值
x
,則運行下面的
Promise 解決過程:
[[Resolve]](promise2, x)
onFulfilled
或者 onRejected
拋出一個異常 e
,則 promise2
必須拒絕執行,並返回拒因 e
onFulfilled
不是函數且 promise1
成功執行, promise2
必須成功執行並返回相同的值onRejected
不是函數且 promise1
拒絕執行, promise2
必須拒絕執行並返回相同的據因Promise 解決過程 是一個抽象的操做,其需輸入一個 promise
和一個值,咱們表示爲 [[Resolve]](promise, x)
,若是 x
有then
方法且看上去像一個 Promise ,解決程序即嘗試使 promise
接受 x
的狀態;不然其用 x
的值來執行 promise
。
這種 thenable 的特性使得 Promise 的實現更具備通用性:只要其暴露出一個遵循 Promise/A+ 協議的 then
方法便可;這同時也使遵循 Promise/A+ 規範的實現能夠與那些不太規範但可用的實現能良好共存。
運行 [[Resolve]](promise, x)
需遵循如下步驟:
x
與 promise
相等若是 promise
和 x
指向同一對象,以 TypeError
爲據因拒絕執行 promise
x
爲 Promise若是 x
爲 Promise ,則使 promise
接受 x
的狀態 注4:
x
處於等待態, promise
需保持爲等待態直至 x
被執行或拒絕x
處於完成態,用相同的值執行 promise
x
處於拒絕態,用相同的據因拒絕 promise
x
爲對象或函數若是 x
爲對象或者函數:
x.then
賦值給 then
注5x.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
方法被調用的那一輪事件循環以後的新執行棧中執行。這個事件隊列能夠採用「宏任務(macro-task)」機制或者「微任務(micro-task)」機制來實現。因爲 promise 的實施代碼自己就是平臺代碼(譯者注: 即都是 JavaScript),故代碼自身在處理在處理程序時可能已經包含一個任務調度隊列或『跳板』)。
譯者注: 這裏說起了 macrotask 和 microtask 兩個概念,這表示異步任務的兩種分類。在掛起任務時,JS 引擎會將全部任務按照類別分到這兩個隊列中,首先在 macrotask 的隊列(這個隊列也被叫作 task queue)中取出第一個任務,執行完畢後取出 microtask 隊列中的全部任務順序執行;以後再取 macrotask 任務,周而復始,直至兩個隊列的任務都取完。
兩個類別的具體分類以下:
setTimeout
, setInterval
, setImmediate
, I/O, UI renderingmicro-task: process.nextTick
, Promises
(這裏指瀏覽器實現的原生 Promise), Object.observe
,MutationObserver
詳見 stackoverflow 解答 或 這篇博客
注2 也就是說在 嚴格模式(strict) 中,函數 this
的值爲 undefined
;在非嚴格模式中其爲全局對象。
注3 代碼實如今知足全部要求的狀況下能夠容許 promise2 === promise1
。每一個實現都要文檔說明其是否容許以及在何種條件下容許 promise2 === promise1
。
注4 整體來講,若是 x
符合當前實現,咱們才認爲它是真正的 promise 。這一規則容許那些特例實現接受符合已知要求的 Promises 狀態。
注5 這步咱們先是存儲了一個指向 x.then
的引用,而後測試並調用該引用,以免屢次訪問 x.then
屬性。這種預防措施確保了該屬性的一致性,由於其值可能在檢索調用時被改變。
TypeError
異常;若是一條無限長的鏈上
thenable 均不相同,那麼遞歸下去永遠是正確的行爲。