深入理解 JavaScript 事件循环与渲染机制

52 阅读1分钟
graph TD
    A[加载JS代码] --> B[解析代码生成AST]
    B --> C[创建全局执行上下文]
    C --> D[变量提升 Hoisting]
    D --> E[逐行执行同步代码]
    E --> F{遇到异步操作}
    F -->|是| G[注册回调到任务队列]
    F -->|否| H[继续执行]
    H --> I[函数调用]
    I -->|是| J[创建函数执行上下文入栈]
    J --> K[执行函数代码]
    K --> L[函数返回后弹出上下文]
    L --> E
    G --> M[调用栈清空]
    M --> N[执行微任务队列]
    N --> O[渲染页面]
    O --> P[取宏任务执行]
    P --> M

核心执行流程

代码解析阶段

  • 词法分析 & 语法分析

JS 引擎将代码解析成 抽象语法树(AST) ,检查语法错误。

  • 创建全局执行上下文(Global Execution Context)

    • 初始化全局对象(如 window
    • 建立作用域链(Scope Chain)
    • 绑定 this(指向全局对象)
    • 变量提升(Hoisting)
      • var 变量初始化为 undefined
      • 函数声明整体提升

执行阶段

  • 逐行执行代码

按顺序执行同步代码(如赋值、函数调用)。

  • 函数调用时

创建函数执行上下文(Function Execution Context)

  • 参数对象(arguments)
  • 局部变量
  • 外部作用域引用(形成闭包)
  • this 绑定(取决于调用方式)

调用栈管理

后进先出(LIFO)结构

每调用一个函数,将其执行上下文压入调用栈;函数返回时弹出。

异步处理机制

事件循环(Event Loop)

  • 同步任务

直接进入调用栈执行

  • 异步任务

宏任务(Macrotasks):setTimeout、setInterval、setImmediate、requestAnimationFrame、DOM 事件、script 标签、I/O (网络请求)

微任务(Microtasks):Promise.then catch finally 、MutationObserver、queueMicrotask、process.nextTick

graph LR
A[执行同步代码] --> B[调用栈清空]
B -->|是| C[执行所有微任务]
C --> D["渲染页面(如果需要)"]
D --> E[取一个宏任务执行]
E --> A