Promise 注册微任务和执行过程

第一段代码

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    return new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
    .then(() => {
    console.log("内部第一个then");
    })
    .then(() => {
    console.log("内部第二个then");
    });
  })
  .then(() => {
    console.log("外部第二个then");
  });

第一个 Promise 里 return 了一个 Promise,那么第一个 Promise 就要等待里面的 Promise 执行完,再执行第二个 return,这个很简单

output:
外部 promise
外部第一个 then
内部 promise
内部第一个 then
内部第二个 then
外部第二个 then

第二段代码

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then");
      })
      .then(() => {
        console.log("内部第二个then");
      });
  })
  .then(() => {
    console.log("外部第二个then");
  });

外部 promise
外部第一个 then
内部 promise
内部第一个 then
外部第二个 then
内部第二个 then

这段代码和第一段代码少了一个 return
我们知道事件队列是”先注册先执行“,及数据结构结构的队列模式。那么我们看一下 Promise 的注册
首先,第一个 Promise 要先执行同步代码,当执行到第二个 Promise 时,里面 resolve,这个时候,外部的第一个 then 的同步操作已经完成了,然后开始注册外部的第二个 then,此时外部的同步任务也都完成了。同步操作完成之后,那么开始执行微任务,我们发现 内部的第一个 then 是优先于外部的第二个 then 的注册,所以会执行完内部的第一个 then 之后,然后注册内部的第二个 then ,然后执行外部的第二个 then ,然后再执行内部的第二个 then。

第三段代码

new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
  .then(() => {
    console.log("外部第一个then");
    let p = new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
    p.then(() => {
        console.log("内部第一个then");
      })
    p.then(() => {
        console.log("内部第二个then");
      });
  })
  .then(() => {
    console.log("外部第二个then");
  });

外部 promise
外部第一个 then
内部 promise
内部第一个 then
内部第二个 then
外部第二个 then

为什么这次又没有交叉执行呢?因为里面将 Promise 赋值给了 p 变量,而 p.then 是属于同步链式调用,所以会同步注册,也会同步执行

第四段代码

let p = new Promise((resolve, reject) => {
  console.log("外部promise");
  resolve();
})
p.then(() => {
    console.log("外部第一个then");
    new Promise((resolve, reject) => {
      console.log("内部promise");
      resolve();
    })
      .then(() => {
        console.log("内部第一个then");
      })
      .then(() => {
        console.log("内部第二个then");
      });
  })
p.then(() => {
    console.log("外部第二个then");
  });

外部 promise
外部第一个 then
内部 promise
外部第二个 then
内部第一个 then
内部第二个 then

这段代码更加诠释了第三段代码的理解度,因为外部 Promise 是赋值后链式调用,那么外层 Promise.then 在同步代码执行救护注册,当走完同步代码,就会执行

async await

这里简单的说一下之前掉过坑的面试题

var a=0;
async function test(){
    let result=await 10 + a;
    console.log(result)
}
test()
a=a+1

我第一次很确定的回答答应 10,答案往往让我惊讶,这也是我之前对 await 理解不深的原因
解释一下为什么是 11,这也和 generator 函数有关系,async await 就是对 generator 函数的封装
await 其实就是相当于 generator 的 yield
上面代码 await 10,只是锁定了 10 这个常量,函数本身是微任务,所以还会继续执行下面的同步代码,等 a+1 执行完,答案就是 11
为什么 await 不是我们理解的等待,我们知道 generator 函数里的 yield 会锁住 yield 后面的变量。上面代码,如果将 await 放在 a 前,那么结果就是 10 了

0