快速了解 setTimeout、Promise、Async/Await 的区别

683 阅读3分钟

这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

背景

学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。

问题

setTimeout、Promise、Async/Await 的区别

首先我们要知道这三个都是异步函数。当面试官问这个问题 的时候,我觉得他应该考的是Event Loop机制。

什么是Event Loop

Event Loop 是一个执行模型,在不同的地方有不同的实现。Android中有Event Loop,NodeJS中有Event Loop, 当然我们浏览器中也有EventLoop。

浏览器的Event Loop

我们用一张图来说明:

image.png

步骤:

  1. 执行全局Script代码(可以认为是一个宏任务);
  2. 全局Script代码执行过程中,产生异步任务,区分宏任务还是微任务,宏任务放宏任务队列,微任务放微任务队列。
  3. 全局Script同步代码执行完毕,调用栈Stack清空。
  4. 从微任务队列队首取一个微任务,放入调用栈Stack去执行,执行中间如果又产生微任务,直接放入当前正在执行的微任务队列末尾,这个时候微任务队列长度减1。
  5. 继续从微任务队首拿出一个微任务,放入调用栈Stack去执行;依次执行,直到微任务队列清空。
  6. 取出宏任务队首的一个宏任务去执行,放入Stack中执行,执行过程中如果有微任务产生,则放入新微任务队列。
  7. 当前的宏任务执行完毕以后,清空调用栈Stack;(注意这里不是宏任务队列执行完毕,是一个宏任务执行完毕)
  8. 重复执行4-7步骤。

再画一张图说明一下:

image.png

了解下浏览器宏任务和微任务有哪些

image.png

这里有个需要注意的地方UI rendering 这个虽然属于微任务,但是它的执行时机是由浏览器决定的。它的执行节点是在所有的微任务执行完毕,下一个宏任务开始之前,执行UI render。并不是说执行完所有的微任务以后,肯定会执行UI render,这个执行时机可能是下次所有微任务执行完毕,也可能是下下次,完全有浏览器决定。

自测一下,验证下我们所学的!

console.log("开始");

setTimeout(() => {
  console.log("timeout-1");
// 第二步:
  Promise.resolve().then(() => {
    console.log("timeout-1:Promise=then");
    Promise.resolve().then(() => {
        console.log("timeout-1:Promise--Promise=then");
      });
  });
},0);

new Promise((resolve, reject) => {
    console.log("Promise-resolve-before");
    resolve(5);
    console.log("Promise-resolve-after");
}).then((data) => {
  console.log("Promise-resolve-then",data);
})

setTimeout(() => {
    console.log("timeout-100");
},100);


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

async function async2() {
    console.log('async2 end')
}

console.log("1");
async1();


console.log("结束");

答案揭晓:

开始=》Promise-resolve-before=》Promise-resolve-after=》1=》async1 start=》async2 end=》结束=》Promise-resolve-then 5 =》async1 end=》timeout-1=》timeout-1:Promise=then=》timeout-1:Promise--Promise=then=》timeout-100

结语

一步一步慢慢来,踏踏实实把活干!