事件循环讲解

事件循环是什么

事件循环是 JS 安排任务的一套规则。

因为 JS 是单线程的,一次只能做一件事,遇到耗时的操作(比如网络请求、定时器),不能卡住等着,得先干别的,等耗时操作完了再回来处理。

任务分两种

JS 把任务分成两种,优先级不一样:

  • 宏任务:setTimeout、setInterval、DOM 事件、Ajax 请求
  • 微任务:Promise.then、async/await 后面的代码

微任务的优先级永远高于宏任务

具体执行顺序是:

  1. 先把手头的同步代码全部执行完
  2. 把队列里所有微任务一次性清空
  3. 从宏任务队列里取出一个执行
  4. 执行完这个宏任务后,再去看微任务队列有没有新的,有就清空
  5. 再取下一个宏任务...循环往复

几个例子=v=

例 1

javascript 复制代码
console.log(1);
setTimeout(() => console.log(2), 0);
Promise.resolve().then(() => console.log(3));
console.log(4);

输出:1 4 3 2

解释:1 和 4 是同步代码,直接输出。Promise.then 是微任务,排在同步后面先执行,所以 3 先于 2 输出。setTimeout 是宏任务,即使延迟是 0 秒,也得等所有微任务清空才轮到它。

例 2

javascript 复制代码
setTimeout(() => {
  console.log('A');
  Promise.resolve().then(() => console.log('B'));
}, 0);

setTimeout(() => console.log('C'), 0);

输出:A B C

A 是第一个宏任务,输出后产生了微任务 B,在当前宏任务结束后立刻清空微任务,然后才取下一个宏任务 C。

例 3

javascript 复制代码
Promise.resolve().then(() => {
  console.log(1);
  setTimeout(() => console.log(2), 0);
});

setTimeout(() => {
  console.log(3);
}, 0);

输出:1 3 2

微任务先执行,输出 1,同时把 2 放进了宏任务队列。然后取宏任务,队列里现在有 3 和 2(按入队顺序),先取 3,再取 2。

例 4

javascript 复制代码
async function test() {
  console.log('a');
  await console.log('b');
  console.log('c');
}
test();
console.log('d');

输出:a b d c

执行 test() 时,先输出 a,然后 await console.log('b') 会先执行 b,但 await 后面的 c 会被当作微任务挂起,继续执行外面的同步代码 d,最后微任务执行输出 c。


常问考点

  1. setTimeout 0 秒不是真的 0 秒,浏览器至少会延迟 4ms,而且还要等主线程空闲和微任务清空。
  2. 微任务里产生的新微任务,会在本轮一并清空,不会留到下一轮宏任务。
  3. 宏任务队列是有顺序的,谁先被放进去谁先被执行。
  4. Promise 的状态变化和 then 的执行时机:then 里的回调是微任务,但前提是 Promise 状态已经变了。如果 Promise 一直 pending,then 永远不会执行。
  5. await 的本质:await 后面的代码相当于被包了一层 Promise.then,所以是微任务。

为什么有时候会搞混

最大的误解来源是:以为 setTimeout 的延迟时间决定执行顺序。

实际上,延迟时间只决定了这个任务什么时候被放进宏任务队列,而不是什么时候被执行。它还要等当前所有同步代码和微任务都处理完,才轮得到它。

另一个容易混淆的点是:宏任务和微任务不在同一个队列里,微任务队列清空后才会去看宏任务队列。所以即使微任务是在宏任务执行过程中产生的,也会在当前宏任务结束后立刻处理,而不是排在下一个宏任务后面。


判断技巧

看到一道输出顺序题,按这个顺序推:

  1. 先找所有同步代码,它们最先执行
  2. 再找微任务(Promise.then、await 后面的代码),它们会在同步代码之后、宏任务之前执行
  3. 最后找宏任务(setTimeout、setInterval),它们最后执行,而且是按入队顺序一个一个来,每执行完一个宏任务就清空一次微任务队列
相关推荐
变与不变8061 小时前
引用类型、内存原理与对象
开发语言·前端·javascript
Highcharts1 小时前
Highcharts实战讲解|散点图+多项式回归曲线复杂图表示列Demo
javascript·数据可视化
梨想橙汁1 小时前
Git 常用命令大全:提交、查看日志、版本回退、文件撤销
前端·javascript
mONESY1 小时前
对话一长上下文就爆?LangChain.js Memory 三种淘汰策略(截断 / 总结 / 检索)实战
javascript
雪芽蓝域zzs2 小时前
第三十二节:部门组织管理(el‑tree 组织树
前端·javascript·vue.js
leoZ2312 小时前
第 7 篇:进阶——校验、联动、列表页
开发语言·前端·javascript·vue.js·人工智能·目标检测·ecmascript
VeryCool2 小时前
别吹了,依赖图像识别的GPT‑6 Astra永远快不起来
前端·javascript·aigc
AC赳赳老秦3 小时前
农产品公开数据应用:OpenClaw 抓取农产品价格、产销公开数据,实现农产品行情动态监测
java·c语言·javascript·python·php·deepseek·openclaw
全栈技术负责人4 小时前
大模型流式输出核心技术:智能 Markdown 渲染引擎方案
前端·javascript·vue.js