javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS事件循环

JavaScript事件循环(Event Loop)的完整指南

作者:环球旅行的蜗牛

在JavaScript的世界中事件循环是一个核心概念,它支撑着JavaScript处理异步操作的能力,让JavaScript能够在单线程环境中优雅地应对复杂的异步编程需求,这篇文章主要介绍了JavaScript事件循环(Event Loop)的相关资料,需要的朋友可以参考下

JavaScript最核心知识点:事件循环、调用栈、宏任务、微任务、异步执行顺序的权威完整指南,包含所有面试必考内容。

一、开篇经典代码(你必须理解)

console.log('Start')
setTimeout(() => console.log('Timeout'), 0)
Promise.resolve().then(() => console.log('Promise'))
console.log('End')

// 输出:
// Start
// End
// Promise
// Timeout

为什么延时 0ms 反而最后执行?答案:事件循环 + 微任务优先机制

二、核心概览

你将学到:

三、事件循环是什么?

事件循环是 JavaScript 实现非阻塞异步的核心机制。即使 JS 是单线程,也能处理网络、定时器、事件,不卡死页面。

餐厅厨房类比(最易懂)

规则:同步先跑完 → 清空所有微任务 → 再执行一个宏任务 → 渲染 → 循环

四、JS 运行时三大组成

1. 调用栈(Call Stack)

2. Web API / Node API(环境提供)

不属于 JS 语法,由浏览器 / Node 实现:

3. 两大队列

宏任务队列(Task Queue)

微任务队列(Microtask Queue)优先级更高!

五、事件循环黄金规则(背下来)

一句话口诀:同步 > 微任务 > 宏任务

六、逐行解析经典面试题

console.log('1')

setTimeout(() => console.log('2'), 0)

Promise.resolve().then(() => console.log('3'))

console.log('4')

执行顺序:

结果:1 → 4 → 3 → 2

七、微任务 vs 宏任务 完整清单

宏任务(Macrotask)

微任务(Microtask)

八、微任务饥饿效应(重要坑)

如果微任务里不断加微任务:宏任务和渲染永远执行不了!页面直接卡死

function loop() {
  Promise.resolve().then(loop)
}
loop() // 页面卡死

九、定时器深度原理

1. setTimeout (0) 不会立即执行

必须等:

2. 最小延时 4ms 规则

嵌套 5 层以上定时器,浏览器强制加 4ms 延迟。

3. 延时不保证!

主线程阻塞时,定时器会超时执行

4. setInterval 会漂移

执行时间会被吞掉,不准。高精度轮询请用 嵌套 setTimeout

十、requestAnimationFrame(rAF)

专门用于动画,和浏览器刷新同步(60fps)。

执行时机:微任务之后 → 渲染之前

优点:

十一、async/await 本质

await 前面的代码同步执行;await 后面的代码 = 微任务

async function foo() {
  console.log(1)
  await Promise.resolve()
  console.log(2) // 微任务
}

十二、最经典 6 道面试题(答案全解析)

题 1:输出顺序

(前面讲过:1 4 3 2)

题 2:嵌套 Promise

setTimeout(()=>console.log(1),0)
Promise.resolve().then(()=>{
  console.log(2)
  Promise.resolve().then(()=>console.log(3))
})
setTimeout(()=>console.log(4),0)
console.log(5)

答案:5 → 2 → 3 → 1 → 4

题 3:await 顺序

console.log(1)
async function fn() {
  console.log(2)
  await Promise.resolve()
  console.log(3)
}
fn()
console.log(4)

答案:1 → 2 → 4 → 3

题 4:var 循环陷阱

for(var i=0;i<3;i++){
  setTimeout(()=>console.log(i),0)
}

答案:3 3 3修复:let / 闭包 / 传参

题 5:阻塞事件循环

长时间同步代码会让定时器超时执行

题 6:微任务饥饿

无限微任务 → 宏任务永远不执行 → 页面卡死。

十三、常见误区(90% 人错)

十四、总结(最简版)

十五、渲染与事件循环的关系

浏览器的渲染流水线严格遵循事件循环的固定节奏:

渲染 每 16ms 一次(60fps),不是每次循环都渲染。如果主线程阻塞,页面就会掉帧、卡顿。

十六、阻塞事件循环的危害

任何耗时超过 16ms 的同步代码都会导致:

典型阻塞代码:

解决方案:

十七、Web Workers(真正并行)

Web Workers 可以创建独立线程,不阻塞主线程。

适合:

十八、任务分拆(Chunking)

把大任务切成小片,每次让出事件循环:

function process(items, processFn) {
  let index = 0
  function next() {
    const chunk = items.slice(index, index + 100)
    index += 100
    chunk.forEach(processFn)
    if (index < items.length) {
      setTimeout(next)
    }
  }
  next()
}

十九、requestIdleCallback

在浏览器空闲时间执行低优先级任务:

requestIdleCallback((deadline) => {
  while (deadline.timeRemaining() > 0) {
    doWork()
  }
})

适合:

二十、事件循环在 Node.js 与浏览器的区别

浏览器

Node.js(libuv)

更复杂,分为多个阶段:

每个阶段跑完后都会清空微任务

二十一、setImmediate 与 setTimeout

在 Node.js 中:

setTimeout(() => console.log('timeout'), 0)
setImmediate(() => console.log('immediate'))

结果不固定。但在 I/O 回调里:setImmediate 一定先执行

二十二、事件循环总结(最终极版)

浏览器完整流程:

终极口诀:

同步优先,微任务插队,宏任务排队,渲染靠边,循环不息。

二十三、必须掌握的 8 个核心结论

总结 

到此这篇关于JavaScript事件循环(Event Loop)的文章就介绍到这了,更多相关JS事件循环内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文