群里看到,不懂就查,查不懂就对线源码。
题目
Promise.resolve().then(() => {
console.log(0)
return Promise.resolve(4)
}).then(res => {
console.log('res: ', res)
})
Promise.resolve().then(() => {
console.log(1);
}).then(() => {
console.log(2);
}).then(() => {
console.log(3);
}).then(() => {
console.log(5);
}).then(() =>{
console.log(6);
})
输出
1 2 3 4 5 6
逻辑
首先设1为.then(() => { console.log(1) })这一个微任务,
其他同理。
一开始执行完两个Promise.resolve()以后:
microTask: `0 1`
Promise.resolve(4)返回一个状态为fulfilled的Promise此时按逻辑应该把4加入到微任务中了,
但是在then中返回fulfilled状态的Promise的话,
Promise内部会将返回的Promise的then方法执行放入到微任务队列中执行。
microTask: 1 Promise.resolve(4).then
microTask: Promise.resolve(4).then 2
而then内部因为Promise.resolve(4)状态已经是fulfilled了,
又申请了个微任务为了让0同步Promise.resolve(4).then的fulfilled的状态,
因为需要等Promise.resolve(4).then内部暴露的Promise初始化完毕后再执行,
所以需要一个微任务等待。
(实际为:Promise.resolve(4).then返回的Promise需要一个微任务进行同步Promise.resolve(4)返回的Promise的fulfilled状态,在同步时顺便也把外部0返回的Promise一并同步了)
注:0返回的Promise是同步Promise.resolve(4).then的状态
microTask: 2 同步状态
microTask: 同步状态 3
microTask: 3 4
最后输出: 1 2 3 4 5 6
证明 Then方法会放入微队列中
0修改为
.then(() => {
console.log(0)
// return Promise.resolve(4)
return {
then(resolve) {
console.log('then')
resolve(4)
},
}
})
输出:
0
1
then
2
res: 4
3
5
6
可以看到then方法是放入了微任务队列中的。
这个then方法中resolve执行直接同步fulfilled状态到0返回的Promise状态上,因此执行完then方法下一个微任务就是输出res了。
源码
我翻找了v8在4.3.65版本还未使用v8 Torque(tq v8内部语言)或C实现的promise.js的源码,在5版本以后就使用C实现了,最新版本使用tq实现。
通过看源码可知Promise.resovle(x) 相当于new Promise(rs => rs(x)),两者行为一致,有兴趣可以试试。
deferred
首先介绍一下deferred,deferred指内部为了链式调用创建的对象,在then方法被调用时返回的就是deferred,Promise的deferred对象也是个Promise(废话,不这样咋链式
据上面源码可知Promise.then/返回Thenable都会创建这个对象。据我感觉最新返回Thenable并不会创建这个对象,直接使用外部的deferred对象
function PromiseDeferred() {
if (this === $Promise) {
// Optimized case, avoid extra closure.
var promise = PromiseInit(new $Promise(promiseRaw));
return {
promise: promise,
resolve: function(x) { PromiseResolve(promise, x) },
reject: function(r) { PromiseReject(promise, r) }
};
} else {
var result = {};
result.promise = new this(function(resolve, reject) {
result.resolve = resolve;
result.reject = reject;
})
return result;
}
}
理解
=>为返回,->为步骤,deferred Object简称为deferred
注:之后的"同步状态"微任务只针对非pending状态
then(onResolve) => deferred
-> onResolve => Promise(fulfilled)
-> Promise(fulfilled).then(deferred.resolve, deferred.reject)
-> 放入一个微任务"同步状态"到外部 deferred 上
-> 以便链式调用
then(onResolve) => deferred
-> onResolve => Thenable
-> deferred.resolve(Thenable)
-> then(onResolve).then(onResolve2, onReject2)
-> deferred.promise.then(onResolve2, onReject2)
-> 不调用这个 .then 据我理解是不会将 Thenable 对象转换成 defeerred 的
-> deferred.promise PromiseState is fulfilled
-> 执行 then 方法,onResolve2 在内部会被包装因此
-> 执行中 Thenable 转换成 thenDeferred 时同步执行 then 方法
-> 根据 then 方法执行后决定 thenDeferred.promise 状态
-> thenDeferred.promise.then(onResolve, onReject)
-> 挂载 deferred.promise.then 的参数到 thenDeferr.promise.then 上
返回Thenable对象:
Promise.resolve()
.then(() => {
console.log(0)
return {
then(resolve) { // 在4.x源码中这儿是同步执行
console.log('then')
resolve(4)
},
}
})
.then(res => {
console.log('res: ', res)
})
相当于
Promise.resolve()
.then(() => {
console.log(0)
})
.then(() => { // 在4.x源码中这儿是同步执行
console.log('then')
return 4
})
.then(res => {
console.log('res: ', res)
})
这是在4.3.65版本的实现逻辑(我的理解,有误您对
源码结论
返回Promise都是需要一个微任务,但是Thenable又不需要,但是这是4.多的代码实现,之后代码改动很大,不过思路大体一致。(应该吧,我看不懂后面的了太菜了
推测
因为这是4.3.65的代码了,所以不符合之前推理的逻辑也正常,虽然这个版本的代码已经挺优雅了,但是可能为了更优雅的实现,Thenable/Promise的then要一视同仁,也得放进微任务中执行,没必要做特殊处理,所以两个的then方法都进入了微任务队列中处理。(我寻思挺合理的
其次我的源码理解的返回Thenable对象的promise后面得再跟一个then方法才会执行Thenable.then,所以需要改动并统一行为。(可能是我理解错误?
那么为什么在目前的版本就是返回Promise是要两个微任务,而Thenable还是一个
讲道理
据我推测在之后版本中,只要有Then都会放入微任务队列执行一下,如果是Promise:
同步状态其实相当于往一个promise的then方法传入(deferred.resolve, deferred.reject)简称这个行为为同步d。
不讨论rejected状态(或者说和 fulfilled状态差不多
PromiseState is fulfilled/Thenable Object:
设 Promise.resolve().then() 返回的 deferred 为 d
Promise.resolve().then(() => Promise.resolve(4))
-> Promise.resolve(4) => Promise(fulfilled) 且非 deferred
-> 内部处理
-> 有 then 方法进行劫持放进微任务队列中执行
-> 由于 then 方法未传入参数, 默认为 onResolve = x => x
-> 即 Promise(fulfilled).then(x => x)
-> pending 状态需要同步
-> Promise(fulfilled).then(x => x).then(同步d)
-> 以上是按照 4.x 逻辑来的,不过 then 方法变成异步罢了
Promise.resolve().then(() => ({ then(rs) { rs(4) }})
-> Thenable 在微任务被调用 then 方法时内部会传入 d.resolve, d.reject 来直接同步外部,
-> 因此只需要一个微任务执行 then 方法即可
新的内部实现应该比这优雅,但是可惜我看不懂
Promise.resolve(4).then(res => res) -> PromiseState is pending:
将当前的promise.then中放入同步状态微任务,
以便可以同步状态到deferred对象上
比如:
Promise.resolve().then(() => Promise.resolve(4).then(res => res))
Promise.resolve().then() 返回的是 deferred(d)
Promise.resolve(4).then(res => res) 返回的也是 deferred(thenD)
因为需要同步状态,因此内部处理挂载上去
Promise.resolve(4).then(res => res).then(同步d)
以便d能及时更新状态
根据
前面代码改成
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4).then(res => res) // pending 状态挂载同步状态微任务
}).then(res => {
console.log('res: ', res)
})
输出:0 1 2 3 4 5 6
结语
一时兴起,大胆猜测,人菜想写,如有错误,轻骂。
内部实现写的好导致的结果,我反正信了。(doge