关于一道promise的诡异题目的理解

要解决的题目以下:面试

Promise.resolve().then(() => {
    console.log(0);
    return Promise.resolve(4);
}).then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
复制代码

输出结果按顺序为0,1,2,3,4,5,6chrome

一、分析

通常遇到Promise.resolve()时,至关于new Promise(resolve => {resolve()})都是同步完成的,不会消耗微任务。 但如下状况时,须要注意,咱们先看三组代码:浏览器

//代码1
new Promise(resolve => {
    resolve(Promise.resolve(4));//resolve了一个Promise
})
.then((res) => {
    console.log(res)
})
复制代码
//代码2
Promise.resolve().then(() => {
    return Promise.resolve(4);//return了一个Promise
})
.then((res) => {
    console.log(res)
})
复制代码
//代码3
Promise.resolve().then(() => {
    return 4;//return了一个Number类型的4
})
.then((res) => {
    console.log(res)
})
复制代码

这三个输出结果,打印出来的都是数字4。微信

咱们能够看出不一样,代码3是咱们最多见的状况。代码3里打印的res是4,和上边return的是一样的数据类型。那么代码1和代码2的res为何不是Object类型的Promise{<fulfilled>: 4}呢?markdown

在通常状况下:函数

Promise.resolve().then(() => {
    return 4;
})
复制代码

这段代码中,Promise.resolve().then是一个构造函数,() => {return 4;}是这个函数的参数,这个函数调用,最后返回一个值为4Promise(即new Promise(resolve => resolve(4)).post

而在ui

new Promise(resolve => {
    resolve(Promise.resolve(4));//resolve了一个Promise
})
复制代码
Promise.resolve().then(() => {
    return Promise.resolve(4);//return了一个Promise
})
复制代码

中,由于js在遇到resolve或者return一个Promise对象时,会先求得这个Promise对象的值,也就是这个Promise的状态为fulfilledrejected的值(假如这个值是'a'),再用这个值做为返回的新的Promised的值,这个新的Promsie(就是new Promise(resolve => resolve('a'))做为下级链式调用的Promisespa

二、结论

在chrome内部实现的Promise和标准的Promise/A+规范存在差别。浏览器内部实现的区别。咱们能够理解为,resolve或者return遇到一个Promise对象时,获得这个Promise的值以后,会把这个值用微任务包装起来,在return值向外传递(由于后边没有.then()了,因此是向父级的外层传递)时,会产生第二个微任务。code

因此代码

//代码1
new Promise(resolve => {
    resolve(Promise.resolve(4));//resolve了一个Promise
})
.then((res) => {
    console.log(res)
})
复制代码

能够理解为

new Promise(resolve => {
    resolve(4);
})
.then()
.then()
.then((res) => {
    console.log(res)
})
复制代码

对应的,代码

//代码2
Promise.resolve().then(() => {
    return Promise.resolve(4);//return了一个Promise
})
.then((res) => {
    console.log(res)
})
复制代码

能够理解为

Promise.resolve()
.then(() => {
    return 4;
})
.then()
.then()
.then((res) => {
    console.log(res)
})
复制代码

这样理解的,和文章开头的题目结果是一致的,核心就是会比正常的return一个非Promise的值时,多两个微任务.then().then()

另外的

Promise.resolve().then(() => {
    return Promise.resolve(Promise.resolve(Promise.resolve(4)))
})
.then(res => {
    console.log(res);
})
复制代码

像这样的return Promise.resolve(Promise.resolve(Promise.resolve(4)))嵌套多层Promise,其实和Promise.resolve(4)是同样的,并不会多产生微任务。由于这两段代码的Promsie状态变为fulfilled的过程并不须要等待。而是拿到它的值以后,在向后运行的时候,会产生微任务。

但若是是

Promise.resolve().then(() => {
    return new Promise(resolve => {
            resolve(4)
    })
    .then(res => {
            return 4.1
    })
    .then(res => {
            return 4.2
    })
})
.then(res => {
    console.log(res);
})
复制代码

这时.then(res => { console.log(res); })想要运行,须要等待前边return 的Promise状态变为fulfilled才行,

new Promise(resolve => {
        resolve(4)
})
.then(res => {
        return 4.1
})
.then(res => {
        return 4.2
})
复制代码

自己是会注册两个微任务的,而拿到它的值以后,在向后运行的时候,又会产生两个任务(包装值一次,return传递一次)。

三、回顾

咱们来回顾下文章开头的题目

Promise.resolve().then(() => {
    console.log(0);
    return Promise.resolve(4);
}).then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
复制代码

按照上边的分析,能够对应转化为

Promise.resolve().then(() => {
    console.log(0);
    return 4;
})
.then()
.then()
.then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
复制代码

运行结果都是0,1,2,3,4,5,6

题目2

Promise.resolve().then(() => {
    return new Promise(resolve => {
         resolve(4)
    })
    .then(res => {
         console.log(res, 'then4_1');
         return 4.1
    })
    .then(res => {
         console.log(res);
         return 4.2
    })
})
.then(res => {
   console.log(res, 'then4_2');
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
复制代码

运行结果为

微信图片_20210411090309.png 题目3

Promise.resolve().then(() => {
    console.log(0);
    return Promise.resolve(Promise.resolve(Promise.resolve(4)));
}).then((res) => {
    console.log(res)
})

Promise.resolve().then(() => {
    console.log(1);
}).then(() => {
    console.log(2);
}).then(() => {
    console.log(3);
}).then(() => {
    console.log(5);
}).then(() =>{
    console.log(6);
})
复制代码

运行结果0,1,2,3,4,5,6

参考文章

深度揭秘 Promise 微任务注册和执行过程

从一道让我失眠的 Promise 面试题开始,深刻分析 Promise 实现细节

相关文章
相关标签/搜索