什么是WebWorker?
WebWorker是HTML5提供的一种浏览器内置的多线程解决方案,通过JavaScript API来创建一个独立于主线程(也就是UI线程)并且可与其并行运行的工作线程。这个新创建的线程可以执行一些长时间运行的计算密集型任务,从而不会阻塞主线程的执行。
众所周知,js最初设计是运行在浏览器中的,为了防止多个线程同时操作DOM,带来渲染冲突问题,所以js执行器被设计成单线程。但随着前端技术的发展,js能力远不止如此,当我们遇到需要大量计算的场景时(比如图像处理、视频解码等),js线程往往会被长时间阻塞,甚至造成页面卡顿,影响用户体验。为了解决单线程带来的这一弊端,Web Worker 应运而生。
通过使用WebWorker,可以享受到如下优点:
- 提高程序的响应速度: WebWorker将代码运行在自己分离出来的线程上,可以避免单线程模式下计算密集型任务造成的UI卡顿问题,提高了程序的响应速度。
- 充分利用多CPU核心:现代电脑普遍具有多个CPU核心,而WebWorker可以比较简单地实现多线程并行处理,充分利用这些CPU核心,提高程序的执行效率。
- 更好的代码结构和模块化:可以将代码分为主线程和工作线程,使代码结构更加合理,同时可以实现更好的项目组织和模块化管理。
需要注意的是,由于WebWorker运行在独立的线程中,因此无法访问DOM,也不能与主线程共享数据,但是它却可以通过postMessage()方法和主线程进行通信,从而实现数据共享和传输。
WebWorker --使用
使用说明:
- 同源限制
分配给 worker 线程的脚本,必须和主线程脚本同源。(否则无法创建 worker,且双方无法通信)
- DOM限制
Worker 工作在子线程,和主线程不太一样。所以并无法操作 DOM \ BOM 等 API。(纯数据处理)
- 全局对象限制
Worker 全局对象不是
window
,所以一些window
上的全局属性和方法也无法访问。(但可以访问Navigator
和Location
接口)
- 通信限制
由于
Worker
单独运行在一个子线程,所以和主线程通信使用发布、订阅的消息机制完成。
- 脚本限制
可以在 Worker 中使用
XMLHttpRequest
来发送异步请求。
- 运行环境限制
Worker 不能运行在
file://
协议下。(不能直接右键打开)
使用WebWorker非常简单,主要包括以下步骤:
- 创建一个新的JavaScript文件,用于编写WebWorker的代码,并在其中编写需要运行的长时间计算(通常是没有依赖关系的独立函数)。
- 在主线程中创建一个WebWorker对象,并指定包含WebWorker代码的JavaScript文件路径。
const myWorker = new Worker("worker.js");
- 使用Worker对象的postMessage()方法向工作线程发送数据。工作线程可以通过onmessage事件监听来接收从主线程传递过来的数据。
// 向工作线程发送消息
myWorker.postMessage(data);
// 在工作线程中监听由主线程发来的消息
self.addEventListener('message', (event) => {
const data = event.data;
// 对接收到的数据进行处理...
postMessage(result);
});
- 在工作线程中使用postMessage()方法将计算结果发送回主线程,并使用主线程上的onmessage事件进行监听。
// 在工作线程中发送消息给主线程
postMessage(result);
// 在主线程中监听由工作线程返回的计算结果
myWorker.onmessage = function(event) {
console.log("Result: " + event.data);
};
- 最后,记得在不需要WebWorker时,通过terminate()方法及时结束该Worker对象,以释放资源。
// 终止一个Worker对象
myWorker.terminate();
需要注意的是,由于WebWorker无法访问DOM对象,在编写工作线程代码时,不能使用window、document等相关对象。
在Web Worker中,也可以使用importScripts()方法导入其他JavaScript文件,以便使用其中的函数和变量。
总的来说,Web Worker使得JavaScript能够在后台线程中运行代码,避免了页面的阻塞,提高了用户体验。