起因

今天遇到一个题目,研究了一天,重新温习了一遍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参数处理这块有问题(按实现思路化简处理后打印的顺序有问题,所以实现思路有和现有的原生处理不太一样)!

下载 (1).jpeg

结论

貌似目前的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')
     })
})

Runningfyy
1.3k 声望661 粉丝

引用和评论

0 条评论