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

  • 页面渲染的稳定性

相关推荐
Oneslide2 分钟前
React 纯前端技术栈报告(2026年)
前端
前端一小卒9 分钟前
AI 时代,前端工程化要重做一遍
前端
橙子家9 小时前
浏览器缓存之【基础键值存储】:Local storage 和 Session storage
前端
星星在线11 小时前
MusicFree:一个「All in One」的个人音乐服务器,让听歌回归简单
前端·后端
IT_陈寒12 小时前
Redis的SETNX并发问题让我加了三天班
前端·人工智能·后端
demo007x12 小时前
Docling 文档转换以及技术架构分析
前端·后端·程序员
京东云开发者13 小时前
京东市民服务又“上新”!这次是黑龙江“龙易办”
前端
袋鱼不重14 小时前
我的神奇同事,AI 用多了居然写了个 Open In Codex
前端·后端·ai编程
竹林81814 小时前
Web3表单签名验证:我用 wagmi 和 ethers 给 DApp 加了一个“免密登录”,踩坑记录全在这了
javascript
用户69903048487514 小时前
try catch使用场景 处理同步代码错误兼容用的
javascript·uni-app