浏览器的多线程和单线程

学习过 JavaScript 的可能会了解,JavaScript 的宿主浏览器只有一个线程运行 JavaScript,除了 JavaScript 的线程,浏览器中单个页面还有一些其他线程,例如:UI 线程负责处理渲染 DOM 元素;GUI 线程用于处理与用户交互的逻辑;网络线程用于发送接收 HTTP 请求;file 线程用于读取文件;定时器线程处理定时任务等等。

1. 单线程原因

为什么不能像很多高级语言一样支持多线程呢?假定 JavaScript 同时有两个线程,一个线程在HTML中创建了一个标签元素,另一个线程删除了这个标签,这时浏览器应该执行什么操作?浏览器中 JavaScript 的主要用途是操作 DOM 。这决定了它只能是单线程,否则会带来很复杂的同步问题。为了避免复杂性,大部分主流浏览器的 JavaScript 运行环境只支持单线程。

2. JavaScript 的事件驱动

既然 JavaScript 只支持单线程,那么有人可能会好奇为什么浏览器中的 JavaScript 可以同时发送多个网络请求或者执行多个事件回调函数呢?

这是因为 JavaScript 是基于事件驱动,当需要进行网络请求时,JavaScript 线程会把请求发送给 network 线程执行,并等待执行结果;当进行文件读取时则调用 file 线程,然后等待结果。然后 JavaScript 会一直轮询事件库 event loop,直到有事件完成,这时浏览器会驱动 JavaScript 去执行事件的回调函数。这就是 JavaScript 的事件驱动模型。

3. web worker诞生

单线程的最大问题是不能利用多核 CPU 的优点,HTML5 推出的 Web Worker 标准,允许 JavaScript 创建多线程,但是子线程受主线程约束,且不得操作 DOM 。所以,这个新标准不会产生多线程同步的问题。

4. 适用场景

Web Worker 能解决传统的 JavaScript 单线程出现的执行阻塞问题,因而适合以下几种业务场景:

  • 并行计算;
  • ajax 轮询;
  • 耗时的函数执行;
  • 数据预处理/加载。

5. 函数介绍

5.1 创建

初始化一个 Web Worker,由于不是所有的浏览器都支持 Web Worker,所以需要判断一下浏览器是否支持:

实例演示
预览 复制