問題
前段時間在使用Promise
的過程中遇到一個很疑惑的地方。大概是這樣的:
const p = new Promise((resolve, reject) => {
return 'hello world'
}).then((result) => {
// expected --> 'hello world'
console.log(result)
})
結果并不能console出hello world
,也就是then
里面的callback
并沒有執行到.
如果并非在Promise
實例內返回值,而是resolve
,則可以console出hello world
const p = new Promise((resolve, reject) => {
resolve('hello world')
}).then((result) => {
// expected --> 'hello world'
console.log(result)
})
一直想當然以為new Promise(callback)
和then(callback)
中callback
的使用是一樣的。略疑惑,于是去看了下then/promise的大致實現,發現和自己的思路完全不一樣,于是做下記錄。
解答
由于是被"bug"吸引過來的,所以第一時間看了Promise
的構造函數
可以發現,由于我們的fn
并沒有調用resolve
,所以res
的值并沒有被記錄,只有調用了reslove
,value
才能夠記錄在Promise
實例的_value
中。
源碼理解
乍一眼看源碼,有種暈暈的感覺。core
里函數也不多,隨手分了下類:
考慮如下:
-
Promise
構造函數: 定義基本狀態。暴露出來的then
方法: 創建新的Promise
; - 考慮日常調用: 由于
Promise
實例需要調用resolve/reject
才能繼續,所以resolve/reject
符合回調模式,resolve
/reject
的后續調用應該是拿來改變各種Promise
內部狀態(突破口); -
Handler
就三行,看上去是包裝了一下onFulfilled
和onRejected
,保留then
所新建的Promise
指針; - 剩余的
handle/handleResolve/doResolve/finale
不是很好理解,留待慢慢分析;
Promise構造函數
結合作者注釋,可整理如下:
內部屬性解釋:
- ** _state** (Int): 記錄的是自身的情況;
- _deferredState (Int): 記錄的是當前promise實例的then的情況;
-
_deferreds (Handler Array): 記錄的是當前
Promise
實例之后的then
(也就是Handler
實例,不理解稍后講解); - _value: 記錄的是當前promise異步完得到的值,可能是實值也有可能是另一個promise.
_state
保存異步情況, 其可能值如下:
0 : 獲取中;
1 : 獲取成功;
2 : 獲取被拒絕(失敗);
3: 需要獲取另外一個異步結果.
_deferredState
看上去有點奇怪,其可能值如下:
0: 初始值;
1: 當前Promise
實例后續只有一個then
的時候;
2: 當前Promise
實例后續有多個then
的時候.
你一定要大叫: "什么鬼!!"
考慮這樣的情況
const p = new Promise(resolve => resolve('a'))
p.then((result) => {
console.log(result) // 'a'
})
p.then((result) => {
console.log(result) // 'a'
})
為何要這么記錄_deferredState
呢?
因為handleResolved
函數每次只處理一個deferred
嘛.
then
唯一暴露出來的then
方法, 做的事情是創建一個新的Promise
實例,并和當前Promise
實例進行_state
和_deferredState
千絲萬縷的關聯。如果我們創建一個Promise
實例,并多次調用then
方法,過程基本上是醬紫的:
resolve / reject
resolve
方法接受(self(當前Promise實例), newValue(異步執行結果))
,干的事情基本符合猜想:
- 處理出錯(
newValue == self || getThen(newValue)失敗
)的情況: 拋鍋給reject
; - 如果發現
newValue
是Promise
實例,當然是標注_state
為adopt another promise
,然后把_value
指向新的Promise實例(newValue
),再進入收尾函數finale
; - 如果發現
newValue
是function
,就跟處理new Promise(fn)
一樣進入doResolve
; - 剩余
newValue
的情況無非就是Number
、String
等值了,此時當前異步已完成,修改狀態_state
為fulfill
,并記錄_value
值為newValue
,再進入收尾函數finale
.
reject
就更簡單了:
- 更改狀態
_state
為reject
,然后進入收尾函數finale
.
收尾函數finale
看上去好厲害哦,不曉得干了些什么事情.
根據resolve
和reject
的處理邏輯,只有在
-
newValue
為Promise
實例; -
Number
等正常值時;
(進入doResolve
線的最后還是要走這兩條路子) - 執行函數失敗時;
才會進入finale
. finale
所做的事情是針對_deferredState
的取值進入不同的處理。
根據之前的認知,_deferredState
記錄的是當前Promise
后續有一個then
還是多個then
。結合代碼來看其實很容易理解啦,就是將多個then
逐一經過handle
處理.
handle
一旦讀懂_deferredState
的作用,handle
簡直不在話下嘛。
調用handle
函數只有兩個地方(safeThen
和then
記為一處,另外是finale
)。這兩塊地方代碼幾乎不重用。不是很理解為何在同一處進行處理。
首先理解while
,根據作者注釋,_state
為3的意義即是: adopt another Promise,也就是這樣的情況:
new Promise(resolve => resolve('a'))
.then(() => {
return new Promise(resolve => resolve('b')) // 標記
})
.then((result) => {
console.log(result) // 'b'
})
之前談到resolve
的時候談到過如果newValue
也是Promise
實例或者是正常值,都會被記錄到_value
中,此處代碼的意義也就是拿到標記處異步的最終結果啦~
- 從
then
或是safeThen
進入: 此時self._state
的值應該還是0
,通過判斷當前Promise
實例的后續個數,_deferreds
收集到后續所有的deferred(其實就是Handler
實例啦),// 講人話就是跟在當前Promise
屁股后面有多少個then
啦 - 從
finale
進入: 此時self._state
的值實際上為1
或者2
,反正是處于解決的狀態,為何不是3
?因為前面while
了嘛。此時不會經過self._state === 0
的判斷,而是直接走向handleResolved
了 // 終于干正事了
handleResolve
handleResolve
簡直是core
代碼里面的高潮嘛~
這里做的處理是從當前Promise
實例過渡到下一個deferred
(也就是Handler
,也就是當前Promise
屁股后面的then
啦)
稍微解釋下asap,看上去應該是類似將當前fn
轉成microtask
,在當前event loop
末尾執行.
如果沒有傳入當前Promise
異步成功,卻沒有傳入onFulfilled
或者異步失敗,卻沒有傳入onRejected
函數的話,就直接resolve
或者reject
掉了。如果有傳入,則先執行cb
,將其結果值作為下一個deferred
(也就是Handler
,也就是當前Promise
屁股后面的then
啦)的newValue
這一段的實現,也就是為何我們能夠使用如下代碼,并拿到c
啦
// 原諒我用個Promise.resolve, 寫Promise實例要打好多字
// 不過`core`內沒有Promise.resolve的實現
Promise.resolve('a')
.then(() => {
return new Promise((resolve) => {
setTimeout(() => {
resolve('b')
}, 100)
})
.then(() => 'c')
})
.then(result => console.log(result))
完結
哈,不是還有doResolve
么,為何doResolve
要用done
標記啊。這個就留給大家仔細琢磨了。
夜深,明天補個總結圖,晚安~