從Promise的Then說起

發表於2016-03-27

Promise讓程式碼變得更人性化

曾經我一直在思考,為什麼程式碼會比較難讀。後來發現,我們平時要閱讀的所有媒體:報紙、書、新聞,我們在閱讀的時候,都是從上到下一直讀下去的,然而,我們的在讀程式碼的時候,經常要跳著去讀,這種閱讀方式其實是反人類的,如果我們能在讀程式碼的時候,也可以從上往下一直讀下去,那麼,程式碼就會變得可讀性提高很多。

 

對比JS中,callback是讓我們跳來跳去讀程式碼最大的罪魁禍首,它讓我們的流程變得混亂,Promise正是為了解決這一問題而產生的。我們來對比一下這個過程

使用Promise之後

很明顯看出,程式碼就變成線性的了,邏輯也變得更加清晰可讀

Promise流程再優化

promse出來之後,大家都有很多的想法,在Promise之上再封裝一層,使用非同步流程更清晰可讀。下面是Abstract-fence 2.0(開發中)的一種解決方案(規範)

Abstract-fence中,function會被分解為多個task

其中, init是task render執行後再執行render, 而render任務又是由getData任務執行後再渲染組成,其中每個task的定義function的引數使用依賴注入傳遞,全域性屬性使用{}包裹

但是在使用Promise.all的過程中,遇到了一個Promise奇怪的問題

Array.prototype.then與Promise.all

很簡單的一段程式碼

毫無疑問,這段程式碼在瀏覽器執行會先列印1,然後再輸出2 但如果在前面增加對then方法的定義,如下程式碼

那麼這段程式碼只會列印出1, 2卻永遠不會執行

查了很多資料,確認promise.all的引數只能接收陣列(類陣列) 

比如如下程式碼就會報錯

所以,Promise.all接收一個Iterator可遍歷物件

對陣列的prototype.then定義為什麼會影響到Promise的行為呢?

Promise A+規範

Promise A+規範看起來還是有點繞,這裡省略掉一些具體的實現細節,將Promise A+更直白的闡述如下

1. Promise then方法需要return一個新的Promise出來,如下

2. 如果promise本身狀態變更到fulfilled之後,呼叫rsFunc,rsFunc的解析值x, 與新的promise2進行promise的解析過程[[Resolve]](promise2, x), x的取值不同,有不同的情況

3. 若x為一個promise,則x完成的最後,再fufill promise2, 對應如下程式碼

4. 若x為一個物件或者函式,如果有then方法,將會執行then方法,then方法this指向x本身,如下

5. 如果x沒有then方法,那麼,x將會做為值來 滿足 promise2

Promise A+給出了一些具體的執行細節,保證了then的順序執行,但在規範中,並未提到Promise.all方法的執行方式

 

為此,檢視bluebird的Promise.all實現方法

BlueBird關於Promise.all實現方法解析

首先,promise中引用promise_array程式碼如下(已略去一些無關程式碼)

promise.all的實現也很簡單

可見,具體的細節在promise_array中的實現

PromiseArray的構造方法中,將引數賦值給this._values,待_init方法中使用

init總結為幾步

1.嘗試轉換引數為Promise物件

2.如果轉換成功,那麼檢查Promise物件的狀態

1. Pending,等待Promise

2. fulfilled, 換取返回值,繼續進行

3. Rejected 終止,返回原因

4. 其他, 終止

上面的程式碼可以看出,一旦陣列的具有then方法,就可被tryConvertToPromise方法轉換為一個Promise物件,如果then方法未實現promise規範,那麼Promise物件就會處於Pending的狀態,Promise.all方法永遠就不會達到fulfilled的條件,問題也就明白了

相關文章