likes
comments
collection
share

promise后续(resolvePromise的奇怪点)

作者站长头像
站长
· 阅读数 13

前言

上个文章我们利用promsieA+规范实现了promise,这可以帮助我们理解大部分的promise知识并且做解决大部分的面试题以及开发问题,但是却还有很多瑕疵,我会用简单的篇幅让大家了解,让promise在大家眼里变的简单

引用

了解 V8 Promise 源码全过程,世界上不再有能困住你的 Promise 题目,[我就是这么肯定这篇文章的干货](引用月夕大佬的话 (juejin.cn)) 对于月夕关于promise在v8引擎下的描述,从源码到例题,身为菜鸡的我不得不重复看很多遍,也只是感受到了皮毛,但是也总结了一些让大家容易理解,并且可以在面试,或者面试题中有很大信息

promise后续(resolvePromise的奇怪点) 图为根据大佬的文章总结的片段导图,接下来为大家阐述

promiseA+关于then的处理

promise后续(resolvePromise的奇怪点) 上一篇文章简单描述过A+关于then的回调函数中关于返回值x的处理,我再次带领大家回顾一遍

A+规范判断x是不是一个promise 采用假设给x一个then的属性,如果then是一个函数那么就认定它是一个promise,并且给这个then赋值(2个函数,相当于executor函数中的resolve,或者reject)并且立马确定好函数中的状态 ,如果不是则在没有抛出错误的情况下通过promise的resolve函数包裹出去(确定为fulfilled状态)如以下代码

promise后续(resolvePromise的奇怪点) A+规范的意思是直接同步执行return里面的代码,然后将其的promise对象确定好,然后return出去,按照这种说法,只有下面的then方法的回调函数才会加入到微任务队列中,我们通过一个例子来演示看看其中到底有什么不一样的地方

2.1 return普通值

let p1 = Promise.resolve(1)
let p2 = p1
    .then((value) => {
        console.log('第一个进入微任务队列')
        return '返回一个普通值'
    })
    .then((value) => {
        console.log('接收返回值:', value)
    })

let p3 = p1
    .then((value) => {
        console.log('第二个进入微任务队列')
        return '我也return一个普通值'
    })
    .then((value) => {
        console.log('接收返回值:', value)
    })

promise后续(resolvePromise的奇怪点) 通过执行结果可以看出再return一个普通值的时候好像确实是同步的把1包装成fulfilled状态的promise对象传递下去,我们再通过一个例子来看

2.2 return 包含then方法的对象

let p1 = Promise.resolve(1)
// 测试用例
let p2 = p1
    .then((value) => {
        console.log('我第一个进入任务队列')
        return {
            then(resolve) {
                resolve('测试值1')
            }
        }
    })
    .then((value) => {
        console.log(value)
    })
// 对比用例
let p3 = p1
    .then((value) => {
        console.log('我第二个进入任务队列')
        return '对比值1'
    })
    .then((value) => {
        console.log(value)
    })

promise后续(resolvePromise的奇怪点) promise后续(resolvePromise的奇怪点) 如图所示:(resolve1不用注释,主要是可以切换3种状态,调用rekject就是失败,什么都不写就是pending)

(注释部分同上一行效果一样),我们惊奇的发现这和return普通值得情况不一样,分析如下

  1. 首先测试用例p1.then进入微任务队列,然后对比用例p1.then进入微任务队列 任务队列:[测试p1.then,对比p1.then]
  2. 然后执行p1.then的代码打印1,然后返回一个对象且有then方法,并且resolve(1),这里如果大家在上一篇文章看过以后就会知道,A+规范在这里通过resovlePromise函数处理这个对象时,已经认定它是一个promise对象,于是将它变为一个fufiled状态的promise对象(因为里面resove了,如果有reject则是rejected的状态,如果啥也没有则是pending状态的promise对象)到这里与浏览器的处理几乎一样,不同的是A+规范认为这是同步的让这个对象转化为promise对象,而V8引擎却是看到这个对象时,开辟了一个微任务队列,将其放入
  3. 所以在执行完p1的微任务队列后,此时微任务队列为:[对比p2.then,测试返回值为对象的函数]
  4. 然后执行对比p1的微任务,然后将对比p1末尾的then的回调函数存入微任务队列,此时微任务队列为:[测试返回值为对象的函数,对比p1末尾then的回调函数]
  5. 后面就是执行测试返回值为对象的函数,然后将测试末尾then的回调函数推入微任务队列,
  6. 到这里按照正常逻辑就推出这个答案

这是第一个不同的地方

总结:当return 一个包含then方法对象的时候会为其创建一个微任务队列

2.3 return一个promise对象

如下面代码

let p1 = Promise.resolve(1)
// 测试用例
let p2 = p1
    .then((value) => {
        console.log(1)
        return new Promise((resolve, reject) => {
            resolve(2)
        })
    })
    .then((value) => {
        console.log(value)
    })
// 对比用例
let p3 = p1
    .then((value) => {
        console.log(3)
        return 4
    })
    .then((value) => {
        console.log(value)
        return 5
    })
    .then((value) => {
        console.log(value)
    })
// 1 3 4 5 2

这个例子p1.then返回的是一个promise状态为fulfilled状态的对象,如果我们按照上面那个题的想法,return一个对象或者是promise对象的时候会新创建一个微任务,那么应该打印 1 3 4 2 5 可2却在最后打印,因为当返回一个promise对象加入微任务队列以后,当执行它的时候,会执行它的then方法再创建一个微任务出来,(简单来说就是return一个promsie对象会创建2个微任务,当然肯定不是一次性创建2个微任务哈) 如图

promise后续(resolvePromise的奇怪点)

promise后续(resolvePromise的奇怪点) 这是月夕大佬在他的文章中描述的,在这里我也思考了很久,虽然用c++实现的源码我也看不太懂 不过感觉掌握这些已经能够应对大部分的面试题了,比如这2道

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);
})

3. 最后

这可能就是语言的魅力吧,遇到奇怪的知识总想把它搞懂,也欢迎大家拿出比较有意思的promise题目和我一起分享。

转载自:https://juejin.cn/post/7152513958736297997
评论
请登录