写给校招生看的js事件循环,async/await相关,做题用

108 阅读3分钟

先下结论

  1. 遇到宏任务并不是马上丢到宏任务队列。而是放到别的地方等待,谁先事件结束,就先放谁进入宏任务队列,然后再取出来。如果两个的定时任务的到期时间是一样的,那就把先执行的丢进宏任务队列。
  2. await 一层,后面的语句就是属于这个宏任务的微任务,并不是看到await马上把他丢到统一的微任务队列。await 一层 的外层如果还有await,那么后面的语句就属于这个宏任务的微任务的微任务。
  3. 注意微任务生成时间,并不是看到await就马上把他丢到相应宏任务的微任务队列。而是必须等await后面的东西执行完了,才丢到微任务队列。假设await后面是一个非promise对象或者执行方法,那就可以注册成微任务,丢进微任务队列。但如果await的方法是返回一个微任务Promise.resolve().then(),则把这个微任务丢到微任务队列。等待这个微任务被执行以后,才会把await后面的代码丢到微任务队列中。

一句话就是。遇到宏任务或微任务不是所有都马上丢进去相应的队列的。可以理解成:

  1. 宏任务就绪了,才丢进来。
  2. 注意微任务的所属宏任务,理解成,每个宏任务是应该有它专属的微任务。
  3. 重点。只有等await 的东西执行完毕,才会把其后的语句封装成微任务,丢到微任务队列

把第三点弄懂,这种题秒杀

后补样例

样例1

var sleep = function (time) {  
  console.log("sleep start");  
  return new Promise(function (resolve, reject) {  
    setTimeout(function () {  
      resolve();  
    }, time);  
  });  
};  
  
async function exec() {  
  await sleep(2000);  
  console.log("sleep end");  
}  
  
async function go() {  
  console.log(Date.now());  
  c1 = exec();  
  console.log("-------1");  
  c2 = exec();  
  console.log(c1, c2);  
  await c1;  
  console.log("-------2");  
  await c2;  
  console.log(c1, c2);  
  console.log(Date.now());  
}  
  
go();

答案1

1693339035562
sleep start
-------1
sleep start
Promise { } Promise { }
sleep end
-------2
sleep end
Promise { undefined } Promise { undefined }
1693339037577

样例2

var sleep = function (time) {  
  console.log("sleep start");  
  return new Promise(function (resolve, reject) {  
    setTimeout(function () {  
      resolve(time);  
    }, time);  
  });  
};  
  
async function exec(time) {  
  let res=await sleep(time);  
  console.log("sleep end",res);  
}  
  
async function go() {  
  console.log(Date.now());  
  c2 = exec(5000);  
  console.log("-------1");  
  c1 = exec(1000);  
  console.log(c1, c2);  
  await c1;  
  console.log("-------2");  
  await c2;  
  console.log(c1, c2);  
  console.log(Date.now());  
}  
  
go();

答案2

1693340406572
sleep start
-------1
sleep start
Promise { } Promise { }
sleep end 1000
-------2
sleep end 5000
Promise { undefined } Promise { undefined }
1693340411579

样例3

console.log('script start')  
  
async function async1() {  
    await async2()  
    console.log('async1 end')  
}  
async function async2() {  
    console.log('async2 end')  
    return Promise.resolve().then(()=>{  
        console.log('async2 end1')  
    })  
}  
async1()  
  
setTimeout(function() {  
    console.log('setTimeout')  
}, 0)  
  
new Promise(resolve => {  
    console.log('Promise')  
    resolve()  
})  
.then(function() {  
    console.log('promise1')  
})  
.then(function() {  
    console.log('promise2')  
})  
  
console.log('script end')

答案3

script start
async2 end
Promise
script end
async2 end1
promise1
promise2
async1 end
setTimeout

快来验证一下是否全错吧!

浏览器和node环境事件循环的区别,一句话

  1. 浏览器的微任务是紧接着所属宏任务后执行完毕的。
  2. node环境是优先执行到时的宏任务,当前没有宏任务才去执行微任务。

所以,node中微任务执行是在宏任务执行的间隙中,并不紧跟着所属宏任务。而浏览器中是紧跟着的。不过,在node11以后,已经尽量和浏览器一致了。就是都是按第1点来。

还有就是node的任务队列会分得更多一点。

微任务队列:

next tick queue:process.nextTick
other queue:Promise.then、queueMicrotask

宏任务队列:

timer queue:setTimeout、setInterval
poll queue:IO check queue:setImmediate
close queue:close

比如按照下面的顺序执行的:
  • next tick mircotask queue
  • other microtask queue
  • timer queue
  • poll queue
  • check queue
  • close queue