Eson Wong's Blog

生活随想、学习笔记、读书总结、创作记录

0%

前端面试题解析之 Promise 和 setTimeout 执行顺序

微任务和宏任务的执行顺序是面试中经常会被问到的问题,这里就来解析一下。

下面的代码中,打印的顺序是什么呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
console.log("script 1");

setTimeout(() => console.log("timeout 1"));

Promise.resolve().then(() => console.log("promise 1"));

Promise.resolve().then(() =>
setTimeout(() => console.log("timeout in promise"))
);

Promise.resolve().then(() => console.log("promise 2"));

setTimeout(() => console.log("timeout 2"));

console.log("script 2");

答案是:

1
2
3
4
5
6
7
[Log] script 1
[Log] script 2
[Log] promise 1
[Log] promise 2
[Log] timeout 1
[Log] timeout 2
[Log] timeout in promise

解析

JavaScript 是单线程的,它的任务调度是基于事件循环的。事件循环中有两种任务队列:微任务队列和宏任务队列。

timeout 中的回调函数会被放到宏任务队列中,而 promise 中的回调函数会被放到微任务队列中。

上面代码的的执行顺序如下:

宏任务队列
微任务队列
script 宏任务

整个 script 作为一个宏任务

console.log("script 1")

setTimeout()

Promise.resolve().then()

Promise.resolve().then()

setTimeout()

console.log("script 2")

() => console.log("promise 1")

() => setTimeout(() => console.log("timeout in promise"))

() => console.log("promise 2")

() => console.log("timeout in promise")

() => console.log("timeout 1")

() => console.log("timeout 2")

安排 () => console.log("timeout 1") 到宏任务队列

安排 () => console.log("promise 1") 到微任务队列

安排 () => console.log("promise 2") 到微任务队列

安排 () => console.log("timeout 2") 到宏任务队列

安排 () => console.log("timeout in promise") 到宏任务队列

宏任务有哪些

  • script
  • setTimeout
  • setInterval
  • setImmediate
  • requestIdleCallback

微任务有哪些

  • Promise 的 then 和 catch
  • process.nextTick (Node.js 环境)
  • MutationObserver (浏览器环境)

补充说明

  1. 宏任务 Macrotask 不是标准的术语, HTML Standard 中的定义是:Task。

  2. Task 和 Macrotask 、 UI rendering 的执行顺序

    Event Loop

    Macrotask Queue

    Macrotask1

    Task

    Macrotask2

    requestAnimationFrame() 的回调

    渲染 UI

请我喝杯咖啡吧!

欢迎关注我的其它发布渠道