← 返回内容列表
基础原理

JavaScript 事件循环到底怎么运行

理解事件循环,可以解释为什么代码书写顺序和实际输出顺序有时并不一致。

先用白话理解

这篇内容在讲什么?

事件循环决定 JavaScript 什么时候执行同步代码、Promise 和定时器。

问题

为什么 Promise 经常比写在前面的 setTimeout 更早输出?

同步代码结束后会先清空微任务,再处理定时器等宏任务。

解决方案
  1. 先标记同步语句
  2. 再找 Promise 微任务
  3. 最后处理 setTimeout
  4. 用控制台验证
完整执行顺序实验示例代码
console.log('1:同步开始')

setTimeout(() => {
  console.log('5:定时器宏任务')
}, 0)

Promise.resolve()
  .then(() => {
    console.log('3:第一个微任务')
    return Promise.resolve()
  })
  .then(() => {
    console.log('4:第二个微任务')
  })

console.log('2:同步结束')

// 输出顺序:1 → 2 → 3 → 4 → 5
01

先执行同步任务

JavaScript 会先完成当前调用栈中的同步代码,只有调用栈清空后,才会处理等待队列中的任务。

02

微任务通常更早执行

Promise 回调属于微任务,当前同步代码结束后会优先清空微任务,再进入 setTimeout 等宏任务。

  • 同步代码
  • Promise 微任务
  • 定时器宏任务
03

不要长时间占用主线程

大量计算会阻塞渲染与点击响应,可拆分任务、使用 Web Worker 或交给服务端处理。

结语

判断最终要回到真实体验

技术方案没有脱离场景的标准答案。把用户任务、业务边界、开发成本和长期维护放在一起评估,才有可能做出稳定、清晰且经得起变化的页面。

照着做的步骤

  1. 先找同步代码
  2. 再找 Promise 微任务
  3. 最后看定时器等宏任务
  4. 用控制台验证顺序

容易踩的坑

  • 认为 setTimeout 0 会立即执行
  • 在主线程做大量计算
  • 混淆代码顺序和执行顺序

术语不用怕

  • 调用栈:当前正在执行的函数
  • 微任务:Promise 等高优先级任务
  • 宏任务:定时器和事件等任务