第 5 卷
- 执行栈:存放正在执行的同步任务,执行栈为空时才会处理任务队列中的异步任务;
- 任务队列:存放待执行的异步任务,分为宏任务队列和微任务队列,遵循「先进先出」原则。
浏览器事件循环的执行流程(核心)
- 执行同步任务:JS引擎从上到下执行同步代码,压入执行栈,执行完成后弹出;
- 执行微任务队列:执行栈为空时,一次性执行完微任务队列中的所有微任务,若执行微任务过程中
产生新的微任务,直接加入当前微任务队列末尾,继续执行;
- 执行宏任务队列:微任务队列清空后,从宏任务队列中取出第一个宏任务执行,执行完成后弹出;
- 重复循环:回到步骤2,依次执行微任务→宏任务→微任务→宏任务,形成事件循环;
- 页面渲染:每执行完一轮微任务+一个宏任务后,浏览器会判断是否需要渲染页面(如修改了
DOM/CSS),渲染完成后再继续循环。
浏览器处理异步操作的过程
异步操作(如定时器、AJAX、事件监听)不会阻塞同步任务,执行流程如下:
- 异步任务触发时(如 setTimeout 到期、AJAX请求成功),不会立即执行,而是进入对应的任务
队列(宏/微任务);
- 同步任务执行完毕,执行栈为空;
- 按事件循环规则,先执行所有微任务,再执行一个宏任务;
- 异步任务执行时,若产生新的异步任务,继续加入对应队列,等待下一轮循环执行。
典型异步任务执行示例
Code block
1console.log('同步任务1'); // 同步任务,立即执行 2
| 3 | setTimeout(() => {//宏任务,加入宏任务队列 |
|---|---|
| 4 | console.log('宏任务setTimeout'); |
| 5 | }, 0); |
6
| 7 | Promise.resolve().then(() => {//微任务,加入微任务队列 |
|---|---|
| 8 | console.log('微任务Promise'); |
| 9 | }); |
| 11 | console.log('同步任务2');//同步任务,立即执行 |
15. 什么是宏任务,什么是微任务?并解释它们在事件循环中的角色和区别
宏任务(Macro Task)
定义
宏任务是优先级较低的异步任务,执行耗时较长,会阻塞页面渲染,浏览器每轮事件循环仅执行一个宏任务,执行完后会触发页面渲染(可选)。
常见的宏任务类型
- 定时器: setTimeout、 setInterval、 setImmediate(IE专属);
- 网络请求:AJAX/fetch请求成功的回调、WebSocket消息回调;
- 事件回调:鼠标/键盘/触摸事件(click/mousemove)、DOMContentLoaded、load;
- 脚本执行:整体JS脚本的执行、 requestAnimationFrame;
- 其他: I/O操作、 MessageChannel。
微任务(Micro Task)
定义
微任务是优先级极高的异步任务,执行耗时极短,不会阻塞页面渲染,浏览器每轮事件循环会一次性执行完所有微任务,执行过程中产生的新微任务会立即加入队列末尾,同步执行。
常见的微任务类型
- Promise相关: Promise.then()、 Promise.catch()、 Promise.finally();
- async/await:await后的代码(本质是Promise.then的语法糖);
- 原生API: MutationObserver(DOM监听)、 queueMicrotask()(手动添加微任务);
- 其他: process.nextTick()(Node.js专属,微任务优先级最高)。
宏任务 vs 微任务核心区别(事件循环中的角色)
- 优先级区别(核心)
微任务优先级 > 宏任务优先级,执行栈为空时,先清空调微任务队列,再执行一个宏任务。
- 执行方式区别
- 微任务:批量执行,一轮事件循环中微任务队列被全部清空,无数量限制;
- 性能影响区别
- 微任务:执行耗时短,无页面阻塞风险,适合处理轻量异步逻辑;
- 宏任务:执行耗时长,可能阻塞页面渲染,适合处理重量级异步逻辑。
- 核心总结口诀
同步任务先执行,微任务队列全清空,宏任务队列取一个,渲染页面再循环。
16. 比较Nodejs和浏览器中的事件循环机制,指出它们的主要差异
Node.js的事件循环是基于libuv库实现的,与浏览器事件循环的核心逻辑一致(单线程+任务队列),但任务分类、执行顺序、阶段划分有本质区别,核心差异如下:
✅ 1. 事件循环的阶段划分不同(核心差异)
浏览器事件循环:无明确阶段,仅分「微任务队列」+「宏任务队列」
执行流程:同步任务 → 微任务队列(全清) → 宏任务队列(取1个) → 渲染 → 重复。
Node.js事件循环:分6个明确的执行阶段,按顺序执行,每个阶段对应一个宏任务队列
执行流程(Node.js 11+ 主流版本):
Code block
1┌───────────────────────────┐ 2│同步任务│
3└─────────────┬─────────────┘ 4│
5┌─────────────▼─────────────┐ 6│process.nextTick()│(微任务,优先级最高,独立于微任务队列)
7└─────────────┬─────────────┘ 8│
9┌─────────────▼─────────────┐ 10│微任务队列│(Promise.then/MutationObserver等)
11└─────────────┬─────────────┘ 12│
13┌─────────────▼─────────────┐ 14│ 阶段1:timers(定时器)│ 执行setTimeout/setInterval到期的回调
15└─────────────┬─────────────┘ 16│
17┌─────────────▼─────────────┐
全站分卷索引 · 10 卷
- 1第 1 卷
- 2第 2 卷
- ◦ 处理样式优先级(!important > 行内样式 > ID选择器 > 类/伪类/属性选择器 > 标签/伪元素选择
- 关键特性
- 6. 详述浏览器加载和执行JavaScript文件的机制
- JS加载执行核心机制(单线程+阻塞特性)
- • 浏览器解析HTML时,遇到 <script> 标签,立即暂停后续HTML解析,发起HTTP请求加载JS文
- • 可通过属性优化加载:
- ◦ async:异步加载,加载完成后立即执行(执行顺序不确定,不阻塞HTML解析,阻塞渲
- ◦ defer:异步加载,HTML解析完成后、DOMContentLoaded事件前执行(执行顺序与标签
- ◦ type="module":ES6模块加载,默认异步,遵循 defer 规则,支持按需加载、作用域隔
- • V8引擎采用即时编译(JIT):将AST转换为字节码,再将热点代码(频繁执行)编译为机器码,
- 关键特性
- • 异步JS(async/defer/module)仅解除对HTML解析的阻塞,仍会阻塞 DOMContentLoaded 事
- 3第 3 卷
- 4第 4 卷
- 5第 5 卷
- 6第 6 卷
- ✅ 2. 微任务的优先级和执行时机不同
- ✅ 3. 宏任务的类型和优先级不同
- ✅ 4. 页面渲染的差异
- • Node.js事件循环:无页面渲染环节,Node.js是服务端运行环境,无需渲染页面,专注于I/O处
- ✅ 5. 异步API的支持差异
- • 浏览器:支持DOM事件、AJAX、requestAnimationFrame、MutationObserver等前端专属异步
- • Node.js:支持文件I/O、网络I/O、child_process、setImmediate、process.nextTick等服务端专
- ✅ 6. 任务队列的数量差异
- ✅ 核心差异总结表
- 17. 描述process.nextTick在Nodejs事件循环中的执行顺序及其与微任务
- 的关系
- process.nextTick的定义
- 7第 7 卷
- 8第 8 卷
- 9第 9 卷
- 10第 10 卷
- • 不再使用的全局变量,手动置空释放:`window.data = null`(浏览器)、`delete global.data`
- • 避免闭包长期引用大对象,若必须引用,业务结束后手动清空闭包引用:`persistentClosure =
- • DOM元素移除前,通过`removeEventListener`移除对应的事件监听(注意:监听函数必须与绑
- • 组件生命周期销毁时(如React的`componentWillUnmount`、Vue的`beforeUnmount`),批
- • 定时器/计时器使用后,务必通过`clearTimeout`/`clearInterval`清理,尤其是在组件销毁、页
- • 将定时器ID存储在实例属性中,便于后续清理:`this.timer = setTimeout(...)`,销毁时执行
- • 避免在JS中长期缓存DOM元素,优先通过`document.querySelector`动态获取,减少不必要的
- • 异步任务(Promise/AJAX)确保完成:无论成功/失败,都调用`resolve/reject`;使用
- • 内存缓存设置上限和过期机制:使用`lru-cache`等成熟缓存库(自动淘汰最近最少使用的缓
- • 优先使用`WeakMap/WeakSet`作为缓存:它们的键是弱引用,当键对应的对象无其他引用时,会
- • 浏览器端:使用Chrome开发者工具(Memory面板),通过HeapSnapshot(堆快照)对比内存
- • Node.js端:使用`--inspect`参数启动服务,通过Chrome开发者工具调试;使用`clinic.js`、