⚡Promise.then方法会慢一拍的问题

118 阅读3分钟

问题出处

这个问题是看一篇大佬的文章有点疑惑才去研究的一个问题(额 其实是有点无聊没事干),正好也加深一下Promise的知识。大佬的文章:这一篇浏览器事件循环,可能会颠覆部分人的对宏任务和微任务的理解🤪🤪🤪 - 掘金 (juejin.cn)

在大佬的文章中有一个例子

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

贴一下大佬的说明:(图片)

2023-08-30_002706.jpg

这里大佬的说明是没有错的,只是我疑惑在了为什么会慢一拍的问题上,接下来是我的验证。

案例1

//  以 函数输出的数字 表示 函数名
Promise.resolve()
      .then(() => {
        console.log(0);
        return 4;  // 那我直接返回一个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 4 2 3 5 6 很明显 f4函数 先于 f2函数 先进入微队列,有没有一种正常了的感觉

首先同步执行完成,当前微队列中有 [f0,f1]两个回调函数,先拿出最前面的 f0 出来执行,执行完毕后面调用了then方法,然后往微队列中加入了 f4 函数,当前微队列 [f1,f4] 这两个回调函数,然后在拿出 f1执行,执行完毕-后面调用了then函数,然后往微队列中加入了 f2 函数,当前微队列 [f4,f2] ,然后调用 f4 函数,后面没有了then方法就不添加队列,当前微队列 [f2],取出 f2 执行后面的顺序执行

那又为什么就改变了返回值就造成了这样的问题呢?那返回其他的呢?

案例二

//  以 函数输出的数字 表示 函数名
Promise.resolve()
      .then(() => {
        console.log(0);
        return 4;  
        // 那我直接返回一个4会怎么样呢?
        // 输出:0 1 4 2 3 5 6
        
        // return '4' 字符串
        // 输出:0 1 4 2 3 5 6
        
        // return [4] 数组
        // 输出:0 1 [4] 2 3 5 6
        
        // return {} 对象
        // 输出:0 1 {} 2 3 5 6
        
        // return undefined | null
        // 输出:0 1 undefined | null 2 3 5 6
        
        // return true | false  Boolean
        // 输出:0 1 Boolean 2 3 5 6
        
        // return Symbol(4)  Symbol
        // 输出:0 1 Symbol(4) 2 3 5 6
        
        // return ()=> 4  返回普通函数也是一样后入队列
        // 输出:0 1 () => 4 2 3 5 6
        
        // return  没有返回值
        // 输出:0 1 undefined 4 2 3 5 6
        
        // 不写 return
        // 输出:0 1 undefined 4 2 3 5 6
        
        // 以上都是一样的输出
        
        // return {  返回一个这样
        //   then: () => 4,
        // };
        // 输出:1 2 3 5 6
        
        // return {    一个对象中带有then方法
        //   then(resolve) {
        //     resolve(4);
        //   },
        // };
        // 输出:0 1 2 4 3 5 6   =====> 不一样了!!!
        
        // return new Promise((resolve) => {
        //   resolve(4);
        // });
        // 输出:0 1 2 3 4 5 6   =====> 与大佬的例子输出一致
        
      })
      .then((res) => {
        console.log(res);
      });

   xxxxxx代码

总结:

根据以上代码明确了一个事情,当你返回了一个不是对象类型或是一个对象没有then方法都会按照一般理解来调用,当返回是一个对象会检测then方法,会自动的调用then方法看有没有使用 resolve() 来返回东西。

也就是Promise的链式调用是根据你的返回值来判断是否把 回调函数 放入队列中,Promise.then方法会自动返回一个Promise对象,当我们伪造了一个对象(带有then方法)浏览器会把这个 回调函数 往后放一位就是慢了一拍,而返回的是一个Promise对象(不论这个Promise是什么状态的)都会往后放两位。

所以 Promise的链式调用是根据你的返回值来判断情况

在总结:

这个在实际中估计十年碰不到一次)M14SEALAJW$TP)X%O~E)~P.png ,水文一篇。