一文彻底理解 Web Worker

215 阅读3分钟

背景

  • Js 是单线程语言,即“同一时间只能执行一个任务”。主要原因是渲染主线程只能有一个。
  • 随着技术发展,Js 单线层模型已经不能满足日益复杂的业务需求以及带来的性能要求。Js 引入的一些如ajax 、setTimeout、requestAnimationFrame等机制不过是通过EventLoop来制造的多线程假象,并没有改变 Js 单线程的本质
  • 在如何保持 Js 单线程特性的同时,充分利用多核处理器来提高性能的背景下,Web Worker 技术应运而生

定义

  • W3C 对 Web Worker 的定义如下:

an API for running scripts in the background independently of any user interface scripts

一个用于在后台独立运行脚本,而不受任何用户界面脚本影响的应用程序接口

  • 兼容性

image.png

  • 简单的 demo
// 主线程代码
const worker = new Worker('worker.js');
worker.postMessage('Hello from the main thread!');
worker.onmessage = (event) => {
  console.log('Message from Web Worker:', event.data);
};

// worker.js
self.onmessage = (event) => {
  console.log('Message from main thread:', event.data);
  self.postMessage('Hello from the Web Worker!');
};

优势

  • 独立运行: 在一个独立的线程中运行,与主线程互不干扰。可以避免主线程因执行耗时操作而卡顿,从而提高页面的响应速度和用户体验
  • 隔离机制: 无法直接访问或操作 DOM 元素。可以防止潜在的页面修改和恶意的攻击,确保网页的安全性和稳定性
  • 多线程异步运行: 允许在标签页进程中创建多个独立线程,每个线程都可以在不同的内核上运行,因此可以实现并行计算

实际应用场景

  • 计算密集型任务: 例如数据分析、图像处理、加密算法等
  • 异步操作: 当需要执行一些异步操作时,例如从服务器获取数据,可以使用Web Worker来避免因为等待异步操作完成而导致的主线程卡顿

image.png

  • 人工智能

局限性

  • 兼容性问题
  • 资源限制:无法直接访问DOM、同源策略、无法读取本地文件等等
  • 编程复杂性
  • 安全性问题
  • 通信效率问题:由于通信效率的限制,Web Worker不适用于实时任务
    • 无法共享内存:与传统多线程编程不同,Web Worker不能直接共享内存,主页面与worker之间的数据传递的是通过拷贝而不是共享来完成的。因此在如大文件传输场景下可能会消耗大量内存和处理时间
    • 数据序列化问题:当主线程与Web Worker之间在数据交换时需要对数据进行序列化和反序列化,序列化会阻塞发送方,而反序列化会阻塞接收方
    • postMessage:postMessage方法本身并不是导致通信效率低下的主要原因,而是由于如Worker线程需要频繁地向主线程发送大量消息,或者消息体积较大等其他因素造成。这可能会导致主线程处理消息的速度跟不上Worker线程发送消息的速度,从而引起通信拥塞和性能问题

有了 Web Worker ,Js 是否真成了一门多线程语言

  • 答案是否定的
  • Js 中的主线程与 Web Worker 之间采用的是消息传递来通信,而不是直接共享内存。这意味着Web Worker之间无法直接共享数据,而传统多线程语言则可以直接共享内存,从而实现更直接和高效的线程间通信

其他类型扩展

  • 除了专用 worker 类型,还有两种特殊的 Web Worker:SharedWorkerServiceWorker
    • SharedWorker 可以在多个浏览器Tab中访问到同一个Worker实例, 可实现多Tab共享数据, 如共享webSocket连接等
    • ServiceWorker 可以拦截和处理网络请求,实现离线缓存、推送通知和其他高级网络功能

应用实例