Skip to content
On this page

T6

node.js

js
setTimeout(() => {	//setTimeout 1
  console.log('setTimeout start');
  Promise.resolve()		// Promises
    .then(() => console.log('promise resolve1'))
    .then(() => console.log('promise resolve2'))
    .then(() => console.log('promise resolve3'))
    .then(() => console.log('promise resolve4'))
  new Promise((resolve) => {	// newPromise
    console.log('promise1 start');
    resolve()
  }).then(() => {
    console.log('promise1 end');
  });
  setTimeout(() => {	// setTimeout 2
    console.log('inner setTimeout')
  })
  console.log('setTimeout end');
}, 0);

function promise2() {		// promise2
  return new Promise((resolve) => {
    console.log('promise2');
    resolve();
  })
}

async function async1() {
  console.log('async1 start');
  await promise2();
  console.log('async1 end');
}

async1();
console.log('script end');

答案

js
async1 start
promise2
script end
async1 end
setTimeout start
promise1 start
setTimeout end
promise resolve1
promise1 end
promise resolve2
promise resolve3
promise resolve4
inner setTimeout

image-20230705205627376

  1. 首先script整体作为同步任务执行,遇到setTimeout定时宏任务时交给定时线程去执行,其结果会放入宏任务队列,主线程挂起当前异步任务继续执行后面的代码。
  2. 执行async1(),async1函数入栈,并为当前函数提供一些变量上下文。首先打印async1 start,遇到await promise2,会执行new Promise()其也是个同步代码,所以会打印promise2,接着会执行resolve(),它返回的是个promise,然后回到async1函数内部,await其实是个语法糖,后面的代码会作为promise的then代码块执行,而then会当做微任务进入微任务队列(promise不清楚的可以看我『异步编程』一文),async1执行完后出栈。
  3. 执行console.log(script end),打印,然后出栈,第一轮同步任务执行完毕。
  4. 同步任务执行完后先看有没有微任务,第2步await后面的语句已经被放入微任务队列了,执行后打印async1 end,微任务队列清空。
  5. 这里没有涉及到视图更新等等。
  6. 主线程接着从任务队列中选取一个最老的宏任务(MacroTask)来执行,这里任务队列中只有一个setTimeout定时任务,首先会判断执行它的时机到了没,如果没到由于没有其他宏任务了,主线程什么都不会做。反之执行其会首先打印setTimeout start。接着执行Promise.resolve()其返回promise是个微任务会放入微任务队列,接着new Promise()执行打印promise1 start,内部也会resolve返回promise也是个微任务放入微任务队列。接着就是setTimeout放入宏任务队列,最后执行setTimeout end
  7. MacroTask执行完毕,清空所有的MircoTask。首先执行promise resolve1,而后的then也是个微任务会被放入当前微任务队列。接着执行promise1 end,接下来又会执行promise resolve2,它也一样返回微任务(和前面重复步骤)直到执行完后面所有的then。
  8. MircoTask执行完后MacroTask Queue就剩下一个setTimeout任务了,合适的时机打印inner setTimeout