theme: fancy
一,前言
近期公司项目比较忙,粘了老博客几篇 Spring 源码来充数,周末腾出时间把 Promise 做个收尾;
在开始 EventLoop 前,我对 Promise 源码部分进行了简单回顾,并更新了【Promise 源码学习】目录 - Promise 知识点梳理;
上一篇,主要介绍了 async/await 的使用和实现原理,主要涉及以下几个点:
- async/await 的使用和功能分析;
- async/await 的实现和原理分析;
本篇,继续介绍浏览器的事件环 EventLoop;
二,EventLoop 简介
EventLoop 是一个执行模型,在浏览器和 Node 中均有不同的实现:
- 在 Node 中,使用 libuv 库实现 EventLoop;
- 在浏览器中,由 Html 规范定义了 EventLoop;
在 JavaScript 代码执行的过程中,可能会进行发送请求、开启定时器等异步操作;
EventLoop 事件循环主要就负责完成相关任务的调度工作;比如:面试中经常问到的执行顺序问题;
备注:EventLoop 是前端领域的重要知识点,也是前端面试的核心考察点;
三,宏任务和微任务
在浏览器的事件循环 EventLoop 执行模型中,涉及宏任务和微任务;
常见宏任务:
- JS 执行栈:js在执行时就是一个宏任务;
- 定时器:setTimeout、setInterval;
- postMessage、MessageChannel;
- IE 下的 setImmediate 方法;
- UI 的界面渲染;
- 事件;
- Ajax;
常见微任务:
- promise.then;
- mutationObserver;
备注:为了方便记忆,可以简单理解为:除以上两种微任务之外,其余均为宏任务;
四,EventLoop 循环机制
浏览器 EventLoop 图示:
重要组成部分:
- 左边 - JS 执行线程:用于执行 JS;(JS 代码为栈型结构执行)
- 右边 - GUI 线程:用于界面的渲染;
- 上边 - 宏任务队列:用于存储运行中产生的宏任务;宏任务队列全局只有一个;
- 下边 - 微任务队列:用于存储运行中产生的微任务;宏任务队列每次循环产生一个;
备注:EventLoop 事件触发线程负责不停地轮训事件队列,并逐个取出进行处理;
代码的执行过程
- 代码执行
JS 代码从上到下执行,当执行到函数时,会创建执行上下文放入 JS 执行栈;
JS 代码中将包含同步代码和异步代码两种;
- 异步操作-宏任务(浏览器 API)
执行过程中,可能发生异步操作(如:定时器、ajax、事件等);
当异步操作的时间到达或成功时,将会被放入到事件队列中;(在事件队列中维护宏任务)
备注:由于队列具有先进先出的特点,因此可以保证代码的执行顺序;
- 事件循环线程
事件循环线程,用于不停地轮训扫描事件队列;
事件循环线程,将对当前执行栈进行检测:若执行栈为空,将会从件队列中取出一个放入执行
备注:事件循环线程是一个单独的线程,所以并不会阻塞 JS 的执行;
- 异步操作-微任务( promise )
代码在执行时,还可能产生一些微任务,如 promise;
在微任务中产生的微任务会被放入当前宏任务下的微任务队列中,即会在当前轮次被情况;
备注:每次执行宏任务时,都会单独创建一个微任务队列;
- GUI 渲染
浏览器渲染的频率是 16.6 ms,所以并不是每次微任务执行完成后都会执行渲染操作;
- 总结:
每次循环一次,都会执行一个宏任务,并清空对应的微任务队列;
五,结尾
本篇,主要介绍了 EventLoop 的执行原理,主要涉及以下几个点:
- EventLoop 简介;
- 宏任务和微任务;
- EventLoop 循环机制
下一篇,待定;