Promise的概念在ES6標准推出來之前已經深入人心,很多框架和第三方庫都有類似的實現。但在深入理解ES6的Promise對象的時候,受之前經驗的影響,很多概念給人似是而非的感覺,其中有一個特別明顯的地方就是ES6中對Promise對象狀態的定義以及resolved概念。
Promise的狀態
Promise對象有三個狀態:pending,fulfilled,rejected,MDN文檔上對Promise對象狀態變化過程用一幅圖描述:
圖中有幾個小細節:
- 圖中的fulfill和reject只是表示指向不同結果,而不是指一個過程,在到達
fulfilled
,rejected
狀態前promise都處在pending
狀態。 settled
包括了fulfilled
和rejected
。- promise只會在
pending
,fulfilled
,rejected
三種狀態下切換。
resolved 和 unresolved
事情在現在看來都很美好,狀態清晰,一目了然。然而,在各種教程中我們會看到這樣一個狀態:resolved
,阮老師的ECMAScript 6 入門中直接把它當作了fulfilled
狀態:
Promise對象代表一個異步操作,有三種狀態:Pending(進行中)、Resolved(已完成,又稱 Fulfilled)和Rejected(已失敗)。
但是MDN中的備注是這樣寫的:
你可能也會聽到一個術語
resolved
,它表示Promise對象處於settled
狀態,或者Promise對象被鎖定在了調用鏈中。
嗯?記不記得上面提到settled
狀態包括fulfilled
和rejected
狀態,那么他至少不能和fulfilled
狀態划等號吧?於是我又搜了搜,發現網上很多文章提到resolved
這個詞時,有人直接當作fulfilled
狀態,有人把它理解為complete
(類似地,fulfilled
是success,rejected
自然就是error或者failure),不過更多人都是很含糊地引用了一下文檔或者阮老師的文章。
不過確實有人直接提出了這個問題:Promise的fulfill和resolve為啥要用兩個詞?,我着重看了賀師俊老師的回答:
因為 fulfill 和 resolve 是不同的。
resolve 只是表示這個 promise 已經確定了,比如 promise A 被 resolve 為 promise B,則 A 已經 resolved 但是並未 fulfilled 。
好吧,我承認我一開始看沒看懂...
不過還好在備注那里MDN放出了一篇幫助理解的文章,Domenic Denicola 的 States and Fates,基本把這兩個概念說清楚了,不過文中只有簡單的文字描述,下面說一下我自己的理解。
state 和 fates
文章將Promise分得更細,分為了狀態(state)和結果(fates,命運,原諒我粗淺的翻譯)。
狀態(state)就是上面提到的三種狀態,需要稍微留意一下的是,文中提到settled
不是一種Promise狀態,只是一種語義上的便利,說白了就是描述Promise確定了而已。
結果(fates)分為resolved
和unresolved
,兩種結果互斥。
- resolved,原文解釋有點繞:
A promise is resolved if trying to resolve or reject it has no effect,當沒辦法去resolve或reject一個promise的時候,這個promise就是resolved的。
- unresolved,原文解釋倒是很簡單:非resolved的promise...... (:з」∠)
顯而易見,只要理解了resolved
的描述,自然就理解unresolved
。首先先提一個Promise的概念,即當Promise的狀態一旦改變,就永久保持該狀態。所以什么時候沒辦法去resolve或reject一個promise對象呢?
- 處於
fulfilled
和rejected
狀態的promise對象,因為他們已經無法改變狀態,而resolve和reject只能對pending
狀態的promise有效。 - 處於
pending
狀態的promise對象也有可能處於resolved
,當promise對象被'鎖定'在另外一個promise對象或者一個非即時返回的thenable
函數中時,也就是上面賀老師提到的promise A 被 resolve 為 promise B這種情況,為了幫助理解,下面用代碼舉個例子。
說明:Chrome(57.0.2987.133)打印promise對象的時候,[[PromiseStatus]]
有三個值:pending,resolved,rejected,這里的resolved
狀態就是指fulfilled
狀態,和我們要說明的resolved
沒有關系,在firefox(49.0.1)中,[[PromiseStatus]]
三個值和標准相同:pending,fulfilled,rejected。為了避免混淆,用firefox做測試
先上一個簡單的代碼:
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'p1 resolve');
});
p1.then(value => {
console.log(value); // p1 resolve
console.log(p1); // Promise { <state>: "fulfilled", <value>: "p1 resolve" }
})
很簡單,一秒后打印p1 resolve,p1對象狀態為fulfilled
。再來看第二例子,在resolve方法中新建了一個Promise對象:
var p1 = new Promise((resolve, reject) => {
function F() {
resolve(new Promise((resolve, reject) => {
console.log(p1); // Promise { <state>: "pending" }
setTimeout(resolve, 2000, 'new Promise resolve');
}))
}
setTimeout(F, 1000, 'p1 resolve');
});
p1.then(function(value) {
console.log(value); // new Promise resolve
console.log(p1); // Promise { <state>: "fulfilled", <value>: "new Promise resolve" }
})
運行一下發現,一秒后打印
Promise { <state>: "pending" }
三秒后打印
new Promise resolve
Promise { <state>: "fulfilled", <value>: "new Promise resolve" }
可以看到,一秒后p1調用了resolve方法,和上一個例子一樣被resolve了,理應變為fulfilled
狀態,但是他被'鎖定'在了一個新的Promise對象中,所以狀態沒有立刻改變並執行onfulfilled
方法,而是依然處於pending
狀態,但是很明顯的是,他的最終結果(這里可以體會到稱為fate的原因,有種宿命的味道)就是fulfilled
狀態,此時的p1不能再resolve或reject。再過了兩秒后新Promise對象resolve,p1執行then(),狀態變為fulfilled
,打印的值也變成了new Promise resolve,而不是p1 resolve。此時打印出的p1的狀態就是fulfilled。
到此,處於pending
狀態的promise對象也有可能處於resolved
情況就很清楚了,至於unresolved,就是promise可以被resolve或reject的時候,此時promise對象一定處於pending
狀態且沒有被resolve或reject為其他Promise對象 / 非即時返回的thenable
函數。而反過來,處於pending
狀態的promise對象不一定是unresolved。
小結
到這里Promise對象的狀態和resolved的概念差不多都清楚了,這篇文章也是我個人理解過程的一個記錄。不過參考到的文章不多,文中的解釋可能並不是很准確,所以在這里貼出來,希望能看看其他人的理解。
一些閑話
說起來,這篇文章離我上一篇文章已經很久了,真是光陰似箭,歲月......算了,還是不感慨了。現在工作確實沒有在學校那會兒充足的時間和精力,總結還是有不少,大部分都在個人的筆記里,沒有貼到博客。有些覺得總結份量不夠,有些覺得個人的理解不深,不敢隨意貼出來。不過在學習一些稍微深入一點的概念的時候,總覺得網上的一些資料並不是很全面和客觀,人雲亦雲的東西太多,自己的理解也是七七八八。所以希望能夠貼出來和大家交流,防止自己閉門造車,后續如果工作時間允許,會發一些這樣的文章,對前端一些比較重要的知識點深入理解。
本文來源:JuFoFu
本文地址:http://www.cnblogs.com/JuFoFu/p/5140302.html
參考文檔:
Domenic Denicola . States and Fates
阮一峰 . Promise 對象
MDN . Promise