5 分钟内理解 JavaScript 事件循环

JavaScript 的 **事件循环** 是其非阻塞、异步特性背后的秘密武器。🤔 听起来很棘手?别担心!在这份 5 分钟指南结束时,您不仅会理解它,还会通过有趣的代码示例看到它的实际作用!🚀

让我们一起解密魔法吧。🧙‍♂️✨

什么是事件循环?🌀

事件循环是 JavaScript 处理异步操作的机制,同时确保主线程不被阻塞。🛠️

以下是幕后工作人员的工作情况:

  • 调用堆栈🗂️:当前正在运行的代码所在的位置。
  • Web API 🌐:处理异步任务,如计时器、HTTP 调用或 DOM 事件。
  • 任务队列🕒:存储等待堆栈清除后运行的回调。
  • 微任务队列⚡:为 Promises 之类的任务保留(优先级高于任务队列)。
  • 可以把它想象成一位忙碌的厨师🧑‍🍳在团队(Web API)的帮助下高效地管理订单(任务)。

    事件循环如何工作

    示例 1:执行顺序

    console.log("Start");
    
    setTimeout(() => console.log("Timeout"), 0);
    
    Promise.resolve("Promise Resolved").then(console.log);
    
    console.log("End");

    **发生了什么?** 🧩

  • console.log("Start") 执行并记录 Start。
  • setTimeout 将其回调发送到任务队列。🕒
  • Promise.resolve 将其 .then 回调发送到微任务队列。⚡
  • console.log("End") 执行并记录 End。
  • 首先处理微任务队列→记录 Promise Resolved。
  • 任务队列被处理→记录超时。
  • **输出:**

    Start
    End
    Promise Resolved
    Timeout

    示例 2:嵌套任务

    console.log("First");
    
    setTimeout(() => {
      console.log("Second");
      Promise.resolve().then(() => console.log("Third"));
    }, 0);
    
    console.log("Fourth");

    **发生了什么?** 🧩

  • 首先记录。
  • setTimeout 将其回调添加到任务队列。
  • 日志第四。
  • 任务队列处理 setTimeout 回调→记录第二个。
  • 在该回调内部,承诺解析→记录第三项。
  • **输出:**

    First
    Fourth
    Second
    Third

    将 Async/Await 添加到 Mix 中

    当使用 `async/await` 时,与 promise 相关的任务会直接进入 **微任务队列**。⚡

    示例 3:混合使用计时器和 Async/Await

    async function fetchData() {
      console.log("Fetching data...");
      return "Data fetched!";
    }
    
    console.log("Start");
    
    fetchData().then(console.log);
    
    setTimeout(() => console.log("Timeout"), 0);
    
    Promise.resolve("Immediate Promise").then(console.log);
    
    console.log("End");

    **发生了什么?** 🧩

  • 日志开始。
  • 调用 fetchData → 日志正在获取数据....
  • setTimeout 将其回调添加到任务队列。
  • Promise.resolve 将其 .then 回调添加到微任务队列。
  • 日志结束。
  • 微任务优先:记录即时承诺。解决 fetchData 承诺 → 记录已获取的数据!
  • 最后,任务队列:日志超时。
  • **输出:**

    Start
    Fetching data...
    End
    Immediate Promise
    Data fetched!
    Timeout

    现实生活中的类比🍔

    想象一个**汉堡店**:

  • 调用堆栈:厨师🧑‍🍳每次做一道菜。
  • Web API:服务员🛎️处理订单和准备。
  • 微任务队列:紧急订单(例如,修复未煮熟的肉饼)将被优先处理。⚡
  • 任务队列:常规订单排队等待。🕒
  • 得益于事件循环(厨师系统),所有任务都井然有序!🎉

    陷阱和最佳实践⚠️💡

  • 避免阻塞事件循环 🚫 长任务可能会冻结您的应用程序: while (true) { // 这会冻结浏览器! } 解决方案:将繁重的任务卸载到 Web Worker。🏗️
  • 计时器并不精确⏱️setTimeout(() => console.log("可能不会在 1 秒后准确运行"), 1000);
  • 了解微任务优先级 ⚡ setTimeout(() => console.log("任务队列"), 0); Promise.resolve().then(() => console.log("微任务队列")); // 输出: // 微任务队列 // 任务队列
  • 明智地使用 Async/Await 🛠️ async function process() { const result = await fetch("https://api.example.com"); console.log(await result.json()); } process();
  • 关键要点🏁

  • 微任务队列任务在任务队列之前运行。
  • 避免大量计算阻塞主线程。
  • 掌握 async/await 以获得干净、高效的异步代码。
  • 通过理解事件循环,你将解锁 JavaScript 开发的超能力。🌟 有自己的问题或示例吗?让我们在评论中聊天吧!💬

    让我们连接 LinkedIn