理解事件循环 Event loop还是必须得理清楚渲染进程与事件循环的流程之间的关系:

浏览器环境下事件循环与渲染进程之间的关系

1. GUI 渲染线程

  • 职责
    • 负责渲染浏览器界面,解析 HTML、CSS。
    • 构建 DOM 树、CSSOM 树、Render 树。
    • 负责页面的布局(Layout/回流)和绘制(Paint/重绘)。
  • 互斥关系与 JS 引擎线程互斥
    • 当 JS 引擎执行时,GUI 渲染线程会被挂起(冻结)。
    • GUI 更新会被保存到一个队列中,等 JS 引擎空闲时立即执行。
    • 原因:防止 JS 在操作 DOM 的同时,GUI 还在渲染,导致渲染前后结果不一致。

2. JS 引擎线程

  • 职责
  • 特性
    • 单线程:一个 Tab 页内只有一个 JS 引擎线程。
  • 互斥关系与 GUI 渲染线程互斥
    • 如果 JS 执行时间过长(如死循环),会导致页面渲染不连贯,出现页面响应阻塞(假死)。

3. 事件触发线程

  • 职责
    • 归属于浏览器而不是 JS 引擎,用来控制事件循环 Event loop
    • 当 JS 执行到异步代码(如鼠标点击、setTimeout、AJAX 等)时,该线程会将对应的任务添加到任务队列的末尾。
  • 触发时机:当事件满足触发条件时,将回调事件放入 JS 引擎的执行队列中等待处理。

4. 定时触发器线程

  • 职责
    • 负责执行 setTimeoutsetInterval 的计时。
  • 原理
    • 非 JS 引擎计时:因为 JS 引擎是单线程的,如果处于阻塞状态会影响计时的准确性,因此由独立线程计时。
    • 通知机制:计时完毕后,通知事件触发线程,将回调任务放入队列。
  • 注意:W3C 标准规定,setTimeout 中低于 4ms 的时间间隔会被算作 4ms。

5. 异步 HTTP 请求线程

  • 职责
    • 负责处理 AJAX、Fetch 等网络请求。
  • 过程
    • 在连接后,通过浏览器新开一个线程进行请求。
    • 检测到状态变更时,如果设置了回调函数,该线程会通知事件触发线程,将回调放入 JS 队列中执行。

6. Web Worker 线程

  • 职责:负责执行耗时的计算任务,而不会阻塞主线程(JS 引擎线程)的 UI 响应。

  • 创建机制:由 JS 引擎线程 通过 new Worker() 指令开启。每创建一个 Worker,渲染进程就会多出一个对应的 Worker 线程。

  • 与 JS 引擎线程的关系

    • 并行不互斥:与主 JS 引擎线程同时运行,互不干扰。
    • 独立环境:Worker 线程有自己独立的内存空间、全局对象(self 而非 window)和执行栈。
    • 通信限制:无法直接操作 DOM,无法访问 windowdocument 等对象。它与主线程之间通过 postMessage 机制进行数据传输(本质上是拷贝或转移内存)。