深入理解 JavaScript 事件循环机制

目录

介绍

同步任务与异步任务

宏任务与微任务是什么

宏任务与微任务是如何工作的(事件循环的执行顺序)

相关案例

介绍

事件循环(event loop)是一种用于处理异步操作的编程模型。在 JavaScript 中,事件循环是指浏览器或 Node.js 运行时环境中负责管理执行顺序的机制。

首先要知道

  • JS是单线程
  • 不能同时执行多个任务
  • 需要调度异步任务

因此,浏览器/Node提供了任务队列/调度机制/事件循环去解决上面问题。

总结来说,就是因为 JavaScript 是单线程的,事件循环是其调度异步任务的机制。

同步任务与异步任务

同步任务:同步任务是指进入调用栈后立即执行、必须等当前任务执行完成后才能执行下一个任务的代码

程序按照顺序依次执行,每个操作都要等待上一个操作完成后才能进行

javascript 复制代码
console.log(1);
console.log(2);
console.log(3);
执行顺序严格是:
1
2
3

异步任务:异步任务是指不会立即进入调用栈执行,而是交给宿主环境处理,等满足条件后再进入任务队列,等待事件循环调度执行的任务。

程序中的操作可以同时进行,不需要等待上一个操作完成才能进行下一个操作)

javascript 复制代码
console.log(1);

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

console.log(3);
//输出
1
3
2
在这里setTimeout 不是立即执行,它交给浏览器计时器模块,到时间后进入宏任务队列,当前宏任务结束后才执行

宏任务与微任务是什么

宏任务

常见:

  • setTimeout

  • setInterval

  • DOM 事件

  • script 整体代码

    • 比如以下这种,会把整个代码块当成一个宏任务执行
    javascript 复制代码
    <script>
      console.log('hello');
    </script>
  • setImmediate(Node)

微任务

微任务的优先级会比宏任务的优先级更高

常见:

  • Promise.then
  • queueMicrotask
  • MutationObserver
  • process.nextTick(Node)

宏任务与微任务是如何工作的(事件循环的执行顺序)

① 执行一个宏任务(比如 script)

script 整体代码就是第一个宏任务

② 在执行宏任务过程中:

  • 同步代码直接进入调用栈执行
  • 遇到微任务 → 加入微任务队列
  • 遇到宏任务 → 加入宏任务队列

③ 当前宏任务执行结束

④ 清空所有微任务队列(一次性清空)

如果微任务里又产生微任务,会继续执行,直到清空。

⑤ 浏览器可能进行一次渲染

⑥ 从宏任务队列中取出下一个宏任务执行

⑦ 重复以上流程

案例

案例1:请解释最后的打印顺序

javascript 复制代码
console.log(1);
Promise.resolve().then(() => {
    console.log(2);
    setTimeout(() => {
        console.log(3);
    }, 0);
});
setTimeout(() => {
    console.log(4);
    new Promise((resolve) => {
        console.log(5);
        resolve();}).then(() => {
            console.log(6);
    });
}, 0);
console.log(7);

//输出:
//1,7,2,4,5,6,3

步骤分析

javascript 复制代码
// step 1执行后  输出1 7
微任务 = [
(() => {
    console.log(2);
    setTimeout(() => {
        console.log(3);
    }, 0);
})
]

宏任务 = [
(() => {
    console.log(4);
    new Promise((resolve) => {
        console.log(5);
        resolve();}).then(() => {
            console.log(6);
    });
})]

// 步骤2 清空微任务队列  输出 2, 将setTimeout加入宏任务
微任务 = [
]

宏任务 = [
(() => {
    console.log(4);
    new Promise((resolve) => {
        console.log(5);
        resolve();}).then(() => {
            console.log(6);
    });
}),
(() => {
        console.log(3);
 })]
// 步骤3 取出宏任务第一个执行, 输出4 以及5,并且将then加入微任务队列
微任务 = [
(() => {
            console.log(6);
    });)
]

宏任务 = [
(() => {
        console.log(3);
 })]
// 步骤四 清空微任务,输出6
微任务 = [
]

宏任务 = [
(() => {
        console.log(3);
 })]
 //步骤5 清空宏任务,输出3
 //最后输出结果 
 //1,7,2,4,5,6,3

总结

JavaScript 作为单线程语言,通过事件循环机制实现了异步任务的调度与执行。整个执行过程围绕"宏任务驱动、微任务插队"展开:

  • 整体 script 作为第一个宏任务执行

  • 宏任务执行结束后,会立即清空所有微任务

  • 微任务清空后,浏览器可能进行一次渲染

  • 随后进入下一轮宏任务

这种设计保证了:

  • 同步代码的顺序执行

  • 异步任务的可控调度

  • Promise 状态变更的及时性

  • 页面渲染的稳定性

相关推荐
睡不着的可乐6 小时前
vue2 和 vue3自定义指令有什么区别,都是怎么实现和使用一个指令
前端·vue.js
闲来没事抠鼻屎6 小时前
Web打印插件实战:轻量化JS打印方案vue-print-designer落地指南
前端
孙凯亮6 小时前
从 SSR 踩坑到 CSR 封神:Nuxt4 全流程终极实战
前端
想努力找到前端实习的呆呆鸟6 小时前
网易云桌面端--精选歌单布局思路记录
前端·javascript·vue.js
Flywith246 小时前
【每日一技】Raycast 实现 scrcpy 的快捷显示隐藏
android·前端
薛端阳7 小时前
OpenClaw的架构优化思路杂想
前端
hi大雄7 小时前
我的 2025 — 名为《开始的勇气》🌱
前端·年终总结
OpenTiny社区7 小时前
TinyRobot:基于 OpenTiny Design 的企业级 AI 交互组件框架
前端·vue.js·ai编程
用户3153247795457 小时前
Tailwind CSS 学习手册
前端·css
踩着两条虫7 小时前
AI 驱动的 Vue3 应用开发平台 深入探究(三):核心概念之引擎架构与生命周期
前端·vue.js·ai编程