背景
- 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
一个用于在后台独立运行脚本,而不受任何用户界面脚本影响的应用程序接口
- 兼容性
- 简单的 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来避免因为等待异步操作完成而导致的主线程卡顿
- 人工智能
局限性
- 兼容性问题
- 资源限制:无法直接访问DOM、同源策略、无法读取本地文件等等
- 编程复杂性
- 安全性问题
- 通信效率问题:由于通信效率的限制,Web Worker不适用于实时任务
- 无法共享内存:与传统多线程编程不同,Web Worker不能直接共享内存,主页面与worker之间的数据传递的是通过
拷贝而不是共享来完成的。因此在如大文件传输场景下可能会消耗大量内存和处理时间 - 数据序列化问题:当主线程与Web Worker之间在数据交换时需要对数据进行序列化和反序列化,
序列化会阻塞发送方,而反序列化会阻塞接收方 - postMessage:
postMessage方法本身并不是导致通信效率低下的主要原因,而是由于如Worker线程需要频繁地向主线程发送大量消息,或者消息体积较大等其他因素造成。这可能会导致主线程处理消息的速度跟不上Worker线程发送消息的速度,从而引起通信拥塞和性能问题
- 无法共享内存:与传统多线程编程不同,Web Worker不能直接共享内存,主页面与worker之间的数据传递的是通过
有了 Web Worker ,Js 是否真成了一门多线程语言
- 答案是否定的
- Js 中的主线程与 Web Worker 之间采用的是消息传递来通信,而不是直接共享内存。这意味着Web Worker之间无法直接共享数据,而传统多线程语言则可以直接共享内存,从而实现更直接和高效的线程间通信
其他类型扩展
- 除了专用 worker 类型,还有两种特殊的 Web Worker:
SharedWorker和ServiceWorker- SharedWorker 可以在多个浏览器Tab中访问到同一个Worker实例, 可实现多Tab共享数据, 如共享webSocket连接等
- ServiceWorker 可以拦截和处理网络请求,实现离线缓存、推送通知和其他高级网络功能