问题
前段时间在使用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
标记啊。这个就留给大家仔细琢磨了。
夜深,明天补个总结图,晚安~