起因
今天遇到一个题目,研究了一天,重新温习了一遍Promise实现,得出来一个不算结论的结论......
这个题经过我的化简长成这样,求代码结果
const p = Promise.resolve()
new Promise(resolve => {
new Promise(resolve => {resolve(p)})
.then(() => {
console.log('after:await')
})
})
let p1 = p.then(() => {
console.log('tick:a')
})
let p2 = p1.then(() => {
console.log('tick:b')
})
let p3 = p2.then(() => {
console.log('tick:c')
})
/*
p.then(() => {
console.log('tick:a')
}).then(() => {
console.log('tick:b')
}).then(() => {
console.log('tick:c')
})
*/
promise实质
我们知道excutor同步执行,then里面的代码异步执行,怎么实现的?
简单的说(这里以成功为例),then里面的代码同步添加到所属promise
的成功回调队列,当excutor里面的参数resolve方法执行的时候,会把成功回调队列里面的代码依次执行
对resolve参数的处理
如果excutor的resolve方法接受的参数是一个Promise对象会怎么样?
首先我在promiseA+规范里面并没有找到这种情况的规定
然后我看了三个promise库,bluebird,es6-promise,promise,都没有对这种情况作处理,也就是当成一个普通的对象
最后阮一峰的es6里面对这种情况有描述
resolve
函数的参数除了正常的值以外,还可能是另一个 Promise 实例,这时p1
的状态就会传递给p2
,p2
的回调函数就会等待p1
的状态改变
应该是新添加的Promise的规定
已有的资料的相关实现
在网上看了很多Promise实现,基本对promise的excutor的resolve方法的实现是这样的promise实现。对参数如果是Promise都是等promise执行完再调resolve
constructor(executor){
...
let resolve = (value) =>{ // 如果resolve的值时一个promise
if(value instanceof Promise){
// 我就让这个promise执行,把成功的结果再次判断
return value.then(resolve,reject) //参数会自动传递到resolve里面去
}
if (this.status === 'pending') {
this.status = 'fulfilled'
this.value = value
this.onFulfilledCallback.forEach(fn => fn(this.value))
}
}
...
注意,这种实现能跑过PromiseA+规范测试用例!
从A+规范的角度没有问题
问题出现
上面的实现相当于让我们的题目中的p执行完后再resolve,按我们现有的实现原理
,我们化简下代码,你们就很清楚了
new Promise(resolve => {
new Promise(resolve => {
//resolve(p)
//相当于变成了
p.then(resolve)
})
.then(() => {
console.log('after:await')
})
})
看起来很对,我们稍微想一想,同步任务执行完,第一轮微任务执行resolve,和打印a,打印完a同时看看有没有返回值,因为是undifined,所以p1的resolve执行
,第二轮微任务await,b,同理第三轮c
执行结果真的是
tick:a
after:await
tick:b
tick:c,
但是 我们如果不化简,实际执行结果是
tick:a
tick:b
after:await
tick:c
这就证明我们现有实现在resolve参数处理这块有问题(按实现思路化简处理后打印的顺序有问题,所以实现思路有和现有的原生处理不太一样)!
结论
貌似目前的promise在resolve参数处理上和a+规范实现的不太一样
如果面试做题遇到的话,求执行顺序,如果参数是一个Promsie实例i,我建议这么处理。具体原因不知道,知道的大佬留言区告诉我一声
var p = Promise.resolve()
new Promise(resolve => {
new Promise(resolve => {
//resolve(p)
//相当于变成了
p.then().then(resolve)
})
.then(() => {
console.log('after:await')
})
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。