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

  • 页面渲染的稳定性

相关推荐
GreenTea3 小时前
GrokBot 核心成员 Lauren Tan:每月交付 2000 个 PR 的人,是怎么用 AI 的
前端·后端·架构
mCell5 小时前
用 Knip 清理 AI Coding 留下的冗余代码
前端·ai编程·前端工程化
笃行3505 小时前
使用Rokid AIUI做了一个童年推箱子游戏
前端
excel6 小时前
前端加密的作用与使用场景
前端
计算机魔术师7 小时前
纽约时报版权诉讼披露:微软高管内部称训练 AI 是人类历史上最大规模劳动窃取
前端
去伪存真8 小时前
大模型的参数量为什么那么大?
前端·人工智能
IT_陈寒8 小时前
Java空指针这次真把我坑惨了
前端·人工智能·后端
高级程序源9 小时前
django大学生创新创业项目管理系统94923-计算机课程设计、毕业设计
javascript·vue.js·spring boot·后端·python·django·课程设计
八荒启·交互动画9 小时前
# Web特效020—让 Web 特效真正动起来:时间循环应该怎么接
前端·webgl·网页特效·八荒启-交互动画·八荒启
动恰客流统计9 小时前
线下零售数字化浪潮下,客流统计的3个核心发展趋势
大数据·前端·人工智能