深入理解 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 状态变更的及时性

  • 页面渲染的稳定性

相关推荐
猫3283 小时前
v-cloak
前端·javascript·vue.js
AC赳赳老秦3 小时前
OpenClaw二次开发实战:编写专属办公自动化技能,适配个性化需求
linux·javascript·人工智能·python·django·测试用例·openclaw
旷世奇才李先生3 小时前
Vue 3\+Vite\+Pinia实战:企业级前端项目架构设计
前端·javascript·vue.js
Ulyanov4 小时前
《PySide6 GUI开发指南:QML核心与实践》 第二篇:QML语法精要——构建声明式UI的基础
java·开发语言·javascript·python·ui·gui·雷达电子对抗系统仿真
聚美智数4 小时前
企业实际控制人查询-公司实控人查询
android·java·javascript
SoaringHeart5 小时前
Flutter进阶:用OverlayEntry 实现所有弹窗效果
前端·flutter
IT_陈寒6 小时前
Vite静态资源加载把我坑惨了
前端·人工智能·后端
herinspace6 小时前
管家婆实用贴-如何分离和附加数据库
开发语言·前端·javascript·数据库·语音识别
小码哥_常7 小时前
从MVC到MVI:一文吃透架构模式进化史
前端
嗷o嗷o7 小时前
Android BLE 的 notify 和 indicate 到底有什么区别
前端