【前端知识体系-NodeJS相关】对于EventLoop(事件轮询)机制你到底了解多少?
EventLoop
1. EventLoop的执行流程图
  ┌───────────────────────┐
┌─>│        timers         │<————— 执行 setTimeout()、setInterval() 的回调
│  └──────────┬────────────┘
|             |<-- 执行所有 Next Tick Queue 以及 MicroTask Queue 的回调
│  ┌──────────┴────────────┐
│  │     pending callbacks │<————— 执行由上一个 Tick 延迟下来的 I/O 回调(待完善,可忽略)
│  └──────────┬────────────┘
|             |<-- 执行所有 Next Tick Queue 以及 MicroTask Queue 的回调
│  ┌──────────┴────────────┐
│  │     idle, prepare     │<————— 内部调用(可忽略)
│  └──────────┬────────────┘
|             |<-- 执行所有 Next Tick Queue 以及 MicroTask Queue 的回调
|             |                   ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │ - (执行几乎所有的回调,除了 close callbacks 以及 timers 调度的回调和 setImmediate() 调度的回调,在恰当的时机将会阻塞在此阶段)
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│             |                   |               |
|             |                   └───────────────┘
|             |<-- 执行所有 Next Tick Queue 以及 MicroTask Queue 的回调
|  ┌──────────┴────────────┐
│  │        check          │<————— setImmediate() 的回调将会在这个阶段执行
│  └──────────┬────────────┘
|             |<-- 执行所有 Next Tick Queue 以及 MicroTask Queue 的回调
│  ┌──────────┴────────────┐
└──┤    close callbacks    │<————— socket.on('close', ...)
- setTimeout/setInterval 属于 timers 类型;
 - setImmediate 属于 check 类型;
 - socket 的 close 事件属于 close callbacks 类型;
 - 其他 MacroTask 都属于 poll 类型。
 - process.nextTick 本质上属于 MicroTask,但是它先于所有其他 MicroTask 执行;
 - 所有 MicroTask 的执行时机,是不同类型 MacroTask 切换的时候。
 - idle/prepare 仅供内部调用,我们可以忽略。
 - pending callbacks 不太常见,我们也可以忽略。
 
2. 执行机制
- 先执行所有类型为 timers 的 MacroTask,然后执行所有的 MicroTask(注意 NextTick 要优先哦);
 - 进入 poll 阶段,执行几乎所有 MacroTask,然后执行所有的 MicroTask;
 - 再执行所有类型为 check 的 MacroTask,然后执行所有的 MicroTask;
 - 再执行所有类型为 close callbacks 的 MacroTask,然后执行所有的 MicroTask;
 - 至此,完成一个 Tick,回到 timers 阶段;
……
如此反复,无穷无尽……

 
2.1 实例理解
const macroTaskList = [
  ['task1'],
  ['task2', 'task3'],
  ['task4'],
]
for (let macroIndex = 0; macroIndex < macroTaskList.length; macroIndex++) {
  const microTaskList = macroTaskList[macroIndex]
  for (let microIndex = 0; microIndex < microTaskList.length; microIndex++) {
    const microTask = microTaskList[microIndex]
    // 添加一个微任务
    if (microIndex === 1) microTaskList.push('special micro task')
    // 执行任务
    console.log(microTask)
  }
  // 添加一个宏任务
  if (macroIndex === 2) macroTaskList.push(['special macro task'])
}
// 输出结果:
// > task1
// > task2
// > task3
// > special micro task
// > task4
// > special macro task
2.2 执行细节分析
2.2.1 试分析下面程序的执行结果
console.log(1)
setTimeout(function() {
    console.log(2)
})
Promise.resolve()
    .then(function() {
        console.log(3)
    })
console.log(4)
2.2.2 执行流程分析
stack(执行栈)、Micro(微任务)、Macro(宏任务)
初始状态: stack:[], Micro: [], Macro: [script]。执行栈为空, 微任务为空, 宏任务队列中有一个整体的 script代码
主线程开始执行, 遇到console.log(1), 首先会打印 1
继续向下执行,遇到 setTimeout异步任务,就将其加入到Macro(宏任务)队列中。等待执行
继续向下执行, 遇到 Promise.resolve也是一个异步任务,单它是微任务,将其加入 Micro(微任务)队列中,等待着行
解析console.log(4), 并且打印4。 当主线程执行完打印的结果依次是 1 和 4。
这时候主线程就会问 任务(异步)队列,有没有微任务要执行,将所有的 Micro(微任务)加入执行栈执行, 打印结果 3
微任务执行完了, 就开始下一轮事件循环, 将第一个 Macro(宏任务)压入执行栈执行, 再次打印 2。

3. 谈一下宏任务与微任务的区别?(面试重点)
[!NOTE]
面试常考点,关键在于理解EventLoop的机制,以及宏任务和微任务的底层原理。
3.1 宏任务
- setTimeout
 - setInterval
 - setImmediate
 - requestAnimationFrame
 
常见的宏任务: setTimeout、setInterval、setImmediate、 script中整体的代码、 I/O操作、 UI渲染等。
3.2 微任务
- process.nextTick
 - MutationObserver
 - Promise.then catch finally
 
常见的微任务有: process.nextTick、Promise和 MutationObserver监听DOM的变化。
3.3 微任务和宏任务的区别
[!NOTE]
- 微任务进入主线程执行是一队一队的, 而宏任务进入主线程是一个一个的。
 - 微任务是在主线程空闲时批量执行, 宏任务是在事件循环下一轮的最开始执行
 
参考文章:
【前端知识体系-NodeJS相关】对于EventLoop(事件轮询)机制你到底了解多少?的更多相关文章
- 前端知识体系-NodeJS相关】NodeJS基础知识全面总结
		
NodeJS基础知识 1. Node的全局对象和全局变量 1.1 全局对象:所有模块都可以调用的 global:表示Node所在的全局环境,类似于浏览器的window对象. process:该对象表示 ...
 - 【前端知识体系-NodeJS相关】NodeJS高频前端面试题整理
		
1. 为什么JavaScript是单线程? 防止DOM渲染冲突的问题: Html5中的Web Worker可以实现多线程 2.什么是任务队列? 任务队列"是一个先进先出的数据结构,排在前面的 ...
 - 【前端知识体系-NodeJS相关】对NodeJS模块机制的理解
		
1. CommonJS模块规范 1.1 模块引用 var math = require('math'); 1.2 模块定义 [!NOTE] 上下文提供exports对象用于导出当前模块的方法和变量,并 ...
 - 【前端知识体系-NodeJS相关】浅谈NodeJS中间件
		
1. 中间件到底是个什么东西呢? [!NOTE] 中间件其是一个函数,在响应发送之前对请求进行一些操作 function middleware(req,res,next){ // 做该干的事 // 做 ...
 - 12.nodejs事件轮询机制
		
一:nodejs事件轮询机制 就是 函数的执行顺序 <script type="text/javascript"> setImmediate(function(){ ...
 - 面试题: nodejs 的事件轮询机制
		
setTimeout(function(){ console.log('setTimeout()执行了') },0) setImmediate(function(){ console.log('set ...
 - JS中的异步以及事件轮询机制
		
一.JS为何是单线程的? JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事.那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊.(在JAVA和c#中的异步 ...
 - nodejs的事件轮询机制
		
1.timers定时器阶段 执行定时器到点的回调函数(所有定时器setTimeout / setInterval的回调函数都在这个阶段执行) 2.idle prepare 准备阶段 TCP错误回调 3 ...
 - 【前端知识体系-JS相关】JS基础知识总结
		
1 变量类型和计算 1.1 值类型和引用类型的区别? 值类型:每个变量都会存储各自的值.不会相互影响 引用类型:不同变量的指针执行了同一个对象(数组,对象,函数) 1.2 typeof可以及检测的数据 ...
 
随机推荐
- s3c2440裸机-代码重定位(2.编程实现代码重定位)
			
代码重定位(2.编程实现代码重定位) 1.引入链接脚本 我们上一节讲述了为什么要重定位代码,那么怎么去重定位代码呢? 上一节我们发现"arm-linux-ld -Ttext 0 -Tdata ...
 - mysql研究跟进
			
count(1)对比 count(*) count(N),N指的是列的序列号,innodb引擎下一般为主键列:count(*),mysql优化器也会将统计列自动优化.所以日常使用区别不大 阿里规范里的 ...
 - 22(8).模型融合---RegionBoost
			
在adaboost当中,样本的权重alpha是固定的,蓝色五角星所在的圈中3个○分错了,红色五角星所在的圈中4个×和1个○都分对了,很容易让人想到,这个模型,对于红色位置的判断更加可信. 动态权重,每 ...
 - spring data JPA entityManager查询 并将查询到的值转为实体对象
			
spring data JPA entityManager查询 并将查询到的值转为实体对象 . https://blog.csdn.net/qq_34791233/article/details/81 ...
 - Markdown数学公式语法
			
详细网址:Markdown数学公式语法
 - 网易发起“疾风”智造IoT联盟,深化“互联网+先进制造业”发展
			
7月26日,2019网易云创峰会在杭州拉开序幕,本次峰会以“连接•洞察•进化”为主题,汇聚行业领袖.技术大咖及业界代表,探讨技术演进与行业应用趋势,研商生态合作升级.共赢未来的道路.上午的主论坛中,网 ...
 - 01-linux介绍
			
一.Linux简介 Linux内核最初只是由芬兰人林纳斯.托瓦兹在大学时出于爱好写出来的,是一套免费使用和自由传播的类Unix操作系统,是基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU ...
 - 软件测试价值提升之路- 第二章"价值实现的起点"读书笔记
			
价值实现的起点 2.1 打破常规 打破哪些已经不适应现在软件开发需要的“准则”,明确需要在什么样的环境下.瞄准什么目标来实现测试的价值 找风险:研发内部测试 测试最基础的是找bug,但需要根据风险找最 ...
 - 深度学习VGG16模型核心模块拆解
			
原文连接:https://blog.csdn.net/qq_40027052/article/details/79015827 注:这篇文章是上面连接作者的文章.在此仅作学习记录作用. 如今深度学习发 ...
 - ASP.NET Server对象
			
Server.HtmlEncode() 执行文本代码Server.HtmlDecode()可以将代码显示 而不是执行它 但是ASP.NET会认为恶意 我们可以将aspx代码开头添加validateRe ...