JS 是单线程的,并且维护着两个任务队列,宏任务队列和微任务队列。
浏览器端的事件循环执行顺序按照下面这三个大步骤进行:
1、JS 首先从宏任务队列中取出一个任务执行。
2、执行完毕,取出微任务队列中的所有微任务,注意是所有。
3、检查是否到了渲染时间,如果是,则触发渲染操作。
说到宏任务,那么哪些任务算是宏任务呢?如下几种便是:
1、setTimeout。
2、setInterval。
3、I/O 事件。
4、UI 渲染。
5、script 代码块。
6、setImmdiate
微任务有如下几种:
1、Promise 的 then 和 catch 回调。
2、MutationObserver。
3、process.nextTick。
输出 1 4 3 5 2 6 7
1、首先依然是一个 script 标签,宏任务队列中只有这一个任务。JS引擎取出该任务执行。
2、执行第一句代码,输出 1。
3、执行到 setTimeout ,由于延迟时间为0 秒,所以会将 setTimeout 的回调函数(宏任务A)加入到宏任务队列中。
4、遇到 Promise ,同步执行 Promise 构造函数中的代码,输出4,由于此时进行了 resolve , promise的状态变成了 fulfilled,所以 then 中的回调(微任务 C)加入到了微任务队列中
5、执行到 script 代码的最后一句,输出 3。
至此,第一个宏任务结束了,JS 引擎开始检查微任务队列中的所有任务。
6、微任务队列中有一个 then 回调,取出执行,此时输出 5。同时同步执行 then 里的 Promise 初始化语句,遇到 第二个 setTimeout ,延时 5 秒,此时由于定时器时间未到,所以第二个 setTimeout 的回调(宏任务B)还不能加入到宏任务队列中
7、执行完微任务C,JS 引擎继续检查宏任务队列,发现宏任务队列中有宏任务 A,取出执行,输出 2。
8、到此,宏任务和微任务队列都空了,JS 引擎开始执行空的事件循环。
9、5秒过后,定时器将回调加入到宏任务队列中。
此时 JS 引擎发现宏任务队列中有了新的任务,即宏任务 B,取出它执行、输出 6,同时 resolve,将 then 回调加入到微任务队列中
10、JS 引擎检查微任务队列,发现微任务 D,将其取出执行,输出 7。