JavaScript 事件循环的工作原理是什么?

描述 JavaScript 事件循环的机制及其工作原理。

异步编程 困难 事件循环 JavaScript 异步

事件循环(Event Loop)是 JavaScript 中处理异步任务的核心机制,它让单线程环境能够高效运行非阻塞代码而不占用主线程。整个架构包含以下关键组件:

  1. JavaScript 单线程特性
    JavaScript 基于单个主线程运行所有代码,无法同时并行执行任务。为避免同步操作阻塞用户交互(如 UI 渲染响应被阻塞导致页面卡顿),通过事件循环实现了异步处理方式。

  2. 运行时组件
    • 调用栈 (Call Stack):LIFO 结构,按顺序执行同步函数。例如:
      function first() { console.log('start'); }
      function second() { setTimeout(handleTimeout, 0); } 
      first(); 
      second();
      

      其中 first() 先压栈运行,后压栈second()触发。

    • 任务队列 (Task Queue / Callback Queue):存放宏任务的回调函数队列,如 setTimeoutsetInterval、UI 事件监听回调等。
    • 微任务队列 (Microtask Queue):专门存放高优先级的微任务回调,如 Promise.then()
    • 事件循环本体 (Event Loop):持续轮询检测调用栈是否为空。一旦栈空,优先检查并清空微任务队列中的所有回调将其推入调用栈执行;最后若有任务待处理,弹出一个宏任务队列中的函数推入调用栈。。
  3. 事件循环工作流程示例
    • 代码依次推入调用栈运行同步部分;
    • 遇到宏任务(如 setTimeout)时将回调添加到宏任务队列;
    • 新产生的微任务会进入独立的微任务队列;
    • 调用栈空后:
      • 所有已排队的微任务将被连续取出执行;
      • 然后才执行一个宏任务回调;
      • 这个过程循环重复直到队列清空。

    模拟代码预测输出序列:

    console.log('脚本启动');
    setTimeout(() => console.log('来自宏任务队列的函数'), 0);
    Promise.resolve().then(() => console.log('来自微任务队列的函数'));
    console.log('脚本结束');
    

    结果打印顺序:

      脚本启动  
      脚本结束  
      来自微任务队列的函数  
      来自宏任务队列的函数
    
  4. 应用优势与重要性
    通过此机制可优化页面执行流畅性,尤其在高负载 I/O 相关操作(AJAX API 调取结果被优先置于微任务后处理以优先完成异步链)。