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

  • 页面渲染的稳定性

相关推荐
张拭心1 分钟前
技术管理笔记:让我“燃尽”的一天
前端
不好听6131 小时前
BFF 架构实战:从前端直调 API 到加入中间层
前端·架构
不好听6131 小时前
前端跨域完全指南:从为什么报错到三种解决方案
前端
三8441 小时前
路由策略/控制 配置双点双向路由重发布
服务器·前端·javascript
Qimooidea2 小时前
祁木 CAD Translator 工程图纸出海实战指南
服务器·前端·安全
小林ixn2 小时前
从BFF到SSE:我在Vue项目里藏了个“AI翻译官”
前端·vue.js·vite
元气少女小圆丶3 小时前
unity发布web嵌入到前端页面的接受参数
前端·unity·webgl
工业HMI实战笔记3 小时前
【拯救HMI】:低碳制造:自动化技术如何助力企业节能降耗
运维·前端·自动化·交互·制造
柒和远方4 小时前
V043:BFF 层流式输出:从前端直连到生产级流式网关的架构演进
javascript·架构·node.js
用户938515635074 小时前
SSE 流式输出的工程化拐点——为什么你需要一个 BFF 层
javascript·人工智能·全栈