> new Promise((resolve, reject) => setTimeout(resolve, 1000, 'foo')) > .then(console.log) > // foo (1s後)
在使用 Promise 的時候,咱們最簡單的理解與用法就是像上面的代碼那樣,把異步結果提供給 resolve 做參數,而後經過給 then 方法傳遞一個自定義函數做爲結果處理函數。但 resolve 和 reject 這兩個參數究竟是什麼?在這背後,它的基本工做方式究竟是怎樣的呢?讓咱們從規範的角度來初步瞭解它吧。 javascript
new Promise(executor)
首先從 Promise 這個構造函數提及,它是全局對象的 Promise 屬性的值,這也就是爲何瀏覽器環境下咱們能直接調用它的緣由,就像 String, Array 這些構造函數同樣。 java
new Promise(executor)
的第一步就像其餘構造函數同樣,按照 Promise 的 prototype 來構建一個新對象,並初始化了幾個內部插槽[[PromiseState]]
,[[PromiseResult]]
,[[PromiseFullfillReactions]]
,[[PromiseRejectReactions]]
,[[PromiseIsHandled]]
來記錄一些相關的信息,能夠從名字來大體推斷出他們的做用,詳情咱們下文再提。這裏它們的初始值除了[[PromiseResult]]
依次爲 "pending",空 list,空 list,false。 react
下一步,ES 會根據這個 promise 對象來生成用來resolve promise的 resolve function
和用來 reject promise 的 reject function
。而後調用 executor,以 resolve function
和 reject function
爲參數,若是在這個過程當中出錯了,就直接 reject promise。最後返回 promise。 數組
那什麼又是 resolve,什麼又是 reject 呢。咱們知道 Promise 的狀態,也就是[[PromiseState]]
有三種值: pending, fullfilled, rejected,用 reject function
就能夠 reject promise,把它的狀態從 pending 變爲rejected。不過 resolve function
既能夠 fullfill promise 來把promise的狀態從 pending 變爲 fullfilled,也能夠用來 reject promise。 promise
那麼 resolve function
和 reject function
到底作了些什麼呢? 瀏覽器
先來看 reject function
,首先在生成它的時候,會給它初始化[[Promise]]
和[[AlreadyResolved]]
插槽,也就是把它和某個 promise 關聯起來。在執行時,會傳入一個參數 reason,並只有當[[AlreadyResolved]]
是 false,也就是還沒 resolve 過、狀態爲 pending 時,纔會調用返回 RejectPromise
、傳入 promise 和 reason 參數來 reject promise,不然返回 undefined。 RejectPromise(promise, reason)
,除了把[[PromiseState]]
從 pending 變爲 rejected 以外,還會把 promise 的結果[[PromiseResult]]
的值設爲 reason,並會取出 promise 的[[PromiseRejectReactions]]
中已存的記錄(相信讀者們已經明白後面還會有一個操做來向這個內部插槽裏存記錄),並用 TriggerPromiseReactions
調用這些記錄作後續處理,並傳入 reject 的緣由 reason。相似的,resolve function
中用到的 FullfillPromise(promise, value)
操做把 promise 的狀態變爲 fulfilled,抽取[[PromiseFullfillReactions]]
的值調用 TriggerPromiseReactions
,並傳入 fulfilled 的結果 value。 微信
TriggerPromiseReactions(reactions, argument)
會調用 EnqueueJob("PromiseJobs", PromiseReactionJob, <<reactions, argument>>)
,待會再詳細說明。 異步
再來看 resolve function
,與 reject function
同樣,在生成它時,會把它與某個 promise 關聯起來。在執行時,咱們傳入的參數叫作 resolution。若是 promise 已經 resolve 過,就返回 undefined。以後的狀況就相對複雜一些了。async
RejectPromise
,reason 參數爲這個 TypeError。FulfillPromise(promise, resolution)
。其他的狀況就是 resolution 是除了自身之外的帶 then 的對象 (Promise) 的狀況了。
RejectPromise
。FulfillPromise
, 。EnqueueJob("PromiseJobs", PromiseResolveThenableJob, <<promise, resolution, thenAction>>)
。在說明 EnqueueJob
以前,先來看看 Job 是個什麼東西。簡單來講,它就像是回調的內部實現機制:「當沒有其餘 ES 在跑時,初始化並執行本身對應的 ES。「。咱們有一個待執行的 FIFO 的 Job 隊列,以及當前的執行環境 running execution context 和 execution context stack,當後二者均爲空時,纔會執行 Job 隊列的第一個。
ES 規定實現裏至少要有兩個 Job 隊列,ScriptJobs
和 PromiseJobs
。當咱們調用 EnqueueJob("PromiseJobs", ...)
時,也就將要完成的 Job 和它們的參數插入到了 PromiseJobs
這個隊列。能夠看到,Promise 下有兩種 Job
PromiseReactionJob(reaction, argument)
[[Capability]]
、[[Type]]
和 [[Handler]]
,分別表示 [[關聯的 promise 及相關的resolve function 和 reject function]]
、[[類別]]
、[[handler]]
。若是用戶沒有給 handler(undefined),就根據類別是 Fulfill 仍是 Reject 來把 argument 看成結果。若是給了 handler,就用它來對 argument 進行進一步處理。最後根據這個結果來用 resolve function 和 reject function 進行處理並返回。PromiseResolveThenableJob(promiseToResolve, thenable, then)
Promise.prototype.then(onfulfilled, onrejected)
首先是建立一個 promiseCapability
,它包含了一個新的 promise 和相關聯的 resolve function
和 reject function
。promise 的產生就是像正常使用 Promise 構造函數那樣構建一個 promise,不過傳給構造函數 executor 是內部自動建立的,做用是把 resolve/reject function 記錄到PromiseCapability
中。
根據 promiseCapability 和 onfulfilled/onrejected 建立兩個分別用於 fulfill 和 reject 的PromiseReaction,也就是 PromiseJobs 裏最終要執行的操做。
若是當前的 promise(this
)是 pending 狀態,就把這兩個 reaction 分別插入到 promise的[[PromiseFulfillReactions]]
和[[PromiseRejectReactions]]
隊列中。但若是此時 promise 已是 fulfilled 或是 rejected 狀態了,就從 promise 的[[PromiseResult]]
取出值 result,做爲 fulfilled 的結果/reject 的緣由,插入到 Job 隊列裏,EnqueueJob("PromiseJobs", PromiseReactionJob, <<reaciton, result>>)
,最後返回 prjomiseCapability 裏存儲的新 promise。Promise.prototype.catch(onrejected)
就是 Promise.prototype.then(undefined, onrejected)
Promise.resolve(x)
像 then 那樣建立一個 promiseCapability
,而後直接調用其中的 resolve function
並傳入要解析的值x,最後返回其中的新 promise.
Promise.all(iterable)
Promise.all也會像 then 那樣建立一個 promiseCapability
,裏面包含着一個新的 promise 及其關聯的 resolve function
和 reject function
,以後就結合迭代器循環:
promiseCapability
的 resolve function
來 resolve 結果數組Promise.resolve
也構建一個新的 promise,而後內部建立一個 Promise.all Resolve Element Function
,傳給這個新 promise 的 then 用來把結果添加到結果數組並使計數器減一。Promise.race(iterable)
一樣的,建立一個 promiseCapability
,而後進行迭代,用 Promise.resolve
來構建一個新的 promise,以後調用這個新 promise 的 then 方法,傳入 promiseCapability 裏的 resolve/reject function
,結合以前提到的 promise 只會 resolve 一次,能夠看到確實頗有 race 的意味。
看到這裏,不知道你們是否對 Promise 有了更深的理解了呢。再往深一步,ES6裏新提出的 async/await 實際上也是應用了 Generator 的思想與 Promise,感興趣的話能夠繼續瞭解一下。
文 / Kacxxia並無做者介紹
本文已由做者受權發佈,版權屬於創宇前端。歡迎註明出處轉載本文。本文連接:https://knownsec-fed.com/2018-08-22-shen-ru-promise/
想要看到更多來自知道創宇開發一線的分享,請搜索關注咱們的微信公衆號:創宇前端(KnownsecFED)。
歡迎點贊、收藏、留言評論、轉發分享和打賞支持咱們。打賞將被徹底轉交給文章做者。
感謝您的閱讀。