调用栈和任务队列 Event Loop 执行顺序

72 阅读2分钟

调用栈

  • 定义
    • 同步任务执行器
      • 后进先出,按顺序执行同步代码
    • 单线程
      • JS只有一个调用栈,同时只能执行一个任务
  • 核心特性
    • 执行同步代码
    • 栈溢出
      • 无限递归同步代码,会导致栈溢出错误(Stack Overflow)
    • 阻塞主线程
      • 调用栈中的任务执行时,主线程会被阻塞,无法处理其他任务

任务队列

  • 定义
    • 异步任务管理器
      • 先进先出,暂存异步任务的回调函数
    • 分类
      • 宏任务
        • setTimerout / setInerval / setImmediate / requestAnimationFrame / IO操作 / UI渲染 / DOM事件回调 等
      • 微任务
        • Promise / async/await / MutationObserver / process.nextTick / queueMicrotask() 等
  • 核心特性
    • 非阻塞
      • 异步任务回调函数不直接进入调用栈,而是被推入任务队列,由Event Loop调度到调用栈中再执行
    • 按优先级处理
      • 微任务优先宏任务
        • 每次调用栈清空后,会先清空所有微任务,再处理下一个宏任务
      • 浏览器渲染时机
        • 通常在微任务清空后 / 宏任务执行前,浏览器kennel进行渲染

Event Loop

  • 概念
    • 事件循环,是一种计算机程序架构,用于等待和发送消息及事件。
  • 产生的背景
    • JS是单线程语言,同时只能执行一个人任务,如果所有任务都是同步执行,会导致主线程阻塞和页面卡死;
  • 作用
    • 负责协调不同类型任务的执行,解决了单线程环境下异步操作的处理问题,避免主线程阻塞,保持页面响应性
  • 意义
    • 避免主线程阻塞,保持页面响应性
    • 高效处理高并发
      • 单线程下通过非阻塞I/O处理大量任务
    • 精准控制执行顺序
      • 理解微任务和宏任务优先级,避免异步代码逻辑错误

Event Loop 执行顺序

  1. 执行调用栈中的同步代码
  2. 清空微任务队列
  3. 浏览器可能渲染页面(重排/重绘)
  4. 从宏任务队列中取出一个任务,推入调用栈执行(每次Event Loop只执行一个宏任务)
  5. 重复1~4步骤形成事件循环

宏任务:

  • 定义
    • 由宿主环境(如浏览器或 Node.js)发起的异步任务
  • 特点
    • 消息队列中的等待被主线程执行的事件,宏任务执行时都会重新创建执行栈

微任务:

  • 定义
    • 由 JavaScript 引擎发起的异步任务,通常与 Promise 相关
    • 是一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前