前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库JavaScript 事件循环
JSJavaScript异步与浏览器

JavaScript 事件循环如何执行?

当前同步代码先执行,随后在检查点清空微任务。定时器回调等待后续调度,浏览器在合适的时机更新渲染。

前端进阶之旅 · 一题精讲更新于 2026.09.05
JavaScript#异步与浏览器#异步编程#事件循环
先看核心答案读代码示例
理解线索

阅读输出题的三条线索

  1. 当前任务把正在执行的同步代码走完
  2. 微任务检查点持续取出微任务,直到为空
  3. 后续调度浏览器可能渲染,再处理任务

本文讨论浏览器,不混用 Node.js 阶段规则

核心回答

先记住这个答案

浏览器中,当前任务里的同步代码先执行。在微任务检查点,运行时会持续处理微任务,直到队列为空,包括期间新加入的微任务。随后浏览器才有机会更新渲染并调度后续任务。Promise 的回调通常是微任务,setTimeout 的回调是计时条件满足后才可调度的任务。

  • Promise 执行器同步运行
  • 微任务检查点会清空队列
  • 渲染有机会发生,不保证每轮发生

宏任务和微任务,区别在哪里?

面试里常说的“宏任务”对应浏览器模型中的 task,例如脚本执行、计时器回调和用户交互相关任务。浏览器可以有不同任务来源与队列,不能把所有异步操作想成一条全局先进先出的队列。

Promise 的 then/catch/finally 回调以及 queueMicrotask 回调属于微任务。微任务不会打断正在执行的同步 JavaScript;到检查点时,队列里的微任务会持续执行。Promise 构造器接收的执行器函数则是同步调用的,不要因为外面写了 new Promise 就把里面的代码全部归为异步。

Promise 和 setTimeout 执行顺序:一道题走完整个过程

在浏览器控制台运行下面这段代码。先记录同步输出,再按入队顺序处理微任务,最后考虑定时器回调。注意 promise 回调内部又创建了一个微任务。

验证“JavaScript 事件循环”中的“Promise 和 setTimeout 执行顺序:一道题走完整个过程”时,应固定输入、运行环境与触发顺序,并同时记录正常结果和失败结果。这样能确认本节结论来自目标机制,而不是缓存、旧状态或偶然时序。

先猜输出,再展开结果JavaScript
console.log('start');

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

Promise.resolve().then(() => {
  console.log('promise');
  queueMicrotask(() => console.log('nested'));
});

queueMicrotask(() => console.log('microtask'));
console.log('end');
查看输出与解释
start
end
promise
microtask
nested
timer

同步阶段打印 start、end;初始微任务队列是 promise、microtask。执行 promise 时把 nested 加到队尾,因此它排在 microtask 后面。微任务处理完,timer 才有机会运行。

同步阶段
setTimeout 只安排后续回调,Promise.then 和 queueMicrotask 登记微任务,当前脚本继续执行到 end。
检查点
promise 先执行并新增 nested;队列随后依次执行 microtask、nested。不是只处理进入检查点时已有的那些任务。
定时器阶段
timer 输出最后。延时为 0 也不意味着立即执行,它仍需要等待主线程可用和后续任务调度。

微任务跑完后,页面一定立刻渲染吗?

不一定。浏览器会根据渲染机会、刷新节奏和页面状态决定是否更新渲染。回答时用“有机会渲染”更准确,不能把每个任务结束机械等同于一次绘制,也不能把渲染简单列成普通宏任务。

如果微任务持续给自己追加微任务,检查点可能长时间无法结束,后续任务和渲染也会被拖延。把大量计算包进 Promise 并不能让它自动离开主线程。可按工作量拆分任务,或把适合的计算交给 Web Worker。

async / await 怎样放进 Event Loop 模型?

调用 async 函数时,遇到首个 await 之前的代码会同步运行。await 会暂停该函数后续部分,待所等待的值兑现后,再通过异步续执行继续运行;即使等待的是已兑现的 Promise,也不会在当前同步调用里直接跑完 await 后面的代码。

分析题目时先写出同步路径,再标出 Promise 何时兑现和续执行何时排入微任务。复杂的 thenable 同化和 Promise 链会引入额外作业,不要用“每个 await 固定等于一轮”这样的口诀替代实际分析。

回答前,多想一步

容易答错的地方

“所有 Promise 里的代码都是微任务”
执行器同步运行,反应回调异步调度。应具体指出是哪一段函数体,不要把整个 Promise 视作一个微任务。
“setTimeout(fn, 0) 必定 4ms 后执行”
延时只是调度条件。HTML 的 4ms 下限与多层嵌套计时器有关,不是所有首次调用都固定 4ms;繁忙主线程和后台策略还会造成额外延迟。
“浏览器与 Node.js 的规则可以混着背”
两者都涉及任务调度与微任务,但 Node.js 还涉及自己的阶段和 process.nextTick。先声明运行环境,再讨论该环境里的顺序。
试着用自己的话回答

面试官还会怎么问?

为什么 Promise 的回调比 setTimeout(fn, 0) 先输出?

对于本页示例,已兑现 Promise 的 then 回调会进入微任务队列,在当前任务之后的检查点被处理。定时器回调要等后续任务调度。这不是任意 Promise 都必定早于任意定时器:若 Promise 还未兑现,回调可能根本还没入队。

在微任务中继续创建微任务,会留到下一轮吗?

不会因为是新加入的就自动延后到下一轮任务。检查点持续取出微任务直至队列为空,因此新微任务也会在同一次检查点处理。这也是无界递归微任务可能阻塞交互的原因。

requestAnimationFrame 属于宏任务还是微任务?

它是浏览器渲染更新流程中的动画帧回调,不能简单当作普通任务队列或微任务队列的一项来排顺序。它通常用于下一次重绘前更新动画状态,实际调用也受页面可见性和渲染调度影响。

从一道题,走向一组知识

把知识连起来

作用域与函数

JavaScript 闭包是什么?

知道回调什么时候执行后,再看它会读到哪份变量。

手写与交互性能

防抖和节流有什么区别?

把定时器调度用于搜索输入和高频交互。

放回知识体系中复习JavaScript 进阶:事件循环

参考资料

  • MDN · 微任务与 queueMicrotask
  • HTML Standard · Event loops
  • HTML Standard · Timers

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 宏任务和微任务,区别在哪里?
  3. Promise 和 setTimeout 执行顺序:一道题走完整个过程
  4. 微任务跑完后,页面一定立刻渲染吗?
  5. async / await 怎样放进 Event Loop 模型?
  6. 容易答错的地方
  7. 面试官还会怎么问
  8. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑