参考

浏览器端
到底什么是事件循环 Event loop in JavaScript (b站搬运的油管视频)
Loupe—可视化查看event loop
https://mp.weixin.qq.com/s/m3a6vjp8-c9a2EYj0cDMmg

深入JavaScript中的EventLoop(b站另外一个搬运的油管视频)(包含异步api回调队列 和 u渲染 两部分动画演示)
对应油管地址,speaker is chrome develoer
https://www.youtube.com/watch?v=cCOL7MC4Pl0&t=1442s

事件循环是如何影响页面渲染的?(非常好博客 理解页面渲染以及 requestAnimationFrame,setTimeout 4ms延迟)
浏览器进程线程详解

Event Loop 这个循环你晓得么?(附GIF详解)(饿了么前端)(附node event loop)

包含浏览器端 和 node端
详解JavaScript中的Event Loop(事件循环)机制 (知乎专栏)
通杀Event Loop面试题! (b站 培训机构讲的 非常好)

task 介绍
Tasks, microtasks, queues and schedules (博客 深入JavaScript中的EventLoop 同一个大佬,这边博客又提到了到底什么是事件循环 Event loop in JavaScript

0 前提

image.png

1. 名词

1.1 微任务 MicroTask

ES原生 Promise

1.2 宏任务 MacroTask

浏览器端: 定时器(setTimeout 和 setInterval)
ajax
UI 渲染
页面交互
DOM事件 requestAnimationFrame

node端: 定时器(setTimeout 和 setInterval)
I/0

1.3 任务队列 task queue

1.4 node端事件循环独有的API

Process.nextTick
setImmediate

2. 浏览器端 event loop

2.1 任务队列分macro task queue和 micro task,一次事件循环,只会从宏任务队列中取出一个执行,然后清空所有微任务队列, 如此循环。

(下面图上 callback queue 没有区分macro 和 micro)
image.png

2.2 UI 渲染和交互的处理是通过 Task Queue 来调度的

image.png
因此耗时任务会导致渲染和交互任务得不到调用,也就是页面“卡死”。
如果设计一个耗时任务

循环 API 队列类型 期间页面能否交互? 每秒执行次数
while(true) 当前任务 701665.8
Promise Microtask Queue 609555.4
setTimeout Task Queue 208.3
requestAnimationFrame Task Queue 59
  1. 单个的耗时任务和 Microtask Queue 都会阻塞页面交互

(因为JavaScript 有 “run-to-completion” 的特性,以及在执行下个task是,要清空当前micro task)

  1. Macro Task 则不影响。 因为 Macro Task 之间浏览器有机会会插入 UI 任务。

扩展:一下代码页面背景是否会闪现一下红色?直觉总会有这样的担心

  1. document.body.style.background = 'red';
  2. document.body.style.background = 'white';

答案:
背景会稳定地呈现白色。 因为 JavaScript “run-to-completion” 的特性,在上述两行代码之间不可能插入渲染任务

3. node端 event loop

image.png
image.png

3.1 node端事件循环不同于浏览器端,一次循环包含六个阶段,主要关注一下三个阶段

  1. timers (定时器执行阶段)
  2. poll (I/0 callback执行阶段,大部分异步api回调在这个阶段执行,)

(不同于 I/0 callbacks 阶段,目前这个部分和poll阶段 从网上看到的资料讲解的不太统一,还没搞明白,暂时把i/o回调放在这里)

  1. check ( setImmediate 执行阶段)

注意: process.nextTick() 不存在以上任何一个阶段,而是介于每个阶段的中间。

事实上,每个阶段都包含三个队列(这里把process.nextTick包含到以上提到的阶段里面了,便于理解)
其中process.nextTick优先级高于promise
image.png

3.2 不确定定性

  1. setTimeout(function() {console.log("setTimeout")}, 0)
  2. setImmediate(() => {
  3. console.log('setImmediate');
  4. });

以上代码 那个先执行?
答案: 随机,都有可能。
因为: image.png