WebWorker
1.基本用法
Worker 创建
javascript
// worker.js 文件对应的是所要执行的任务
var worker = new Worker('worker.js');Worker 通信
主线程与 Worker 之间通信采用的是消息传递机制,具体如下:
主线程
javascript
// postMessage 发送消息
worker.postMessage('Main Hello World');
// 监听消息
worker.onmessage = function (event) {
console.log('Main Received message ' + event.data);
}
// worker 内部出错时
worker.onerror = function (error) { }其他线程
js
// worker 线程
self.postMessage('Worker Hello World');
self.onmessage = function (event) {
console.log('Worker Received message ' + event.data);
}self 是一个全局对象,它代表了 Worker 线程自身的环境。在 Worker 文件中,self 取代了在普通浏览器环境中全局可用的 window 对象。
Worker 销毁
worker 执行完任务后,通过销毁可以释放资源。
javascript
// 主线程
worker.terminate()
// worker 线程
self.close()- worker.terminate() 是在主线程中调用的方法,用于立即终止 Worker 线程。当你调用 terminate() 时,Worker 线程会被强制停止,它不会有机会完成当前正在执行的任务或进行清理工作。这是主线程对 Worker 线程的一种单向控制。
- self.close() 是在 Worker 线程内部调用的方法,用于优雅地关闭 Worker 线程。当你从 Worker 线程内部调用 close() 时,Worker 线程会完成当前正在执行的任务,然后关闭自己。这种方式允许 Worker 线程在关闭前进行必要的清理工作。
2.注意事项
WebWorker 的使用需要遵循如下一些注意事项:
1、同源策略:分配给 Worker 线程运行的脚本文件,必须与主线程的脚本文件同源。
2、文件限制:Worker 脚本必须来源于网络文件,不能直接运行内敛 JavaScript 或从本地文件系统加载脚本。
3、作用域隔离:每个 Worker 都有自己的全局执行环境,不能在 Worker 中访问主线程中的JavaScript 对象。
4、结构化克隆:传递给Worker的数据通过结构化克隆算法进行复制。这意味着可以传递大多数JavaScript数据结构,但是不能传递DOM元素或函数。
5、DOM 限制:Worker 中无法读取 DOM 对比,也无法使用document、window、parent这些对象。但是,Worker 线程可以navigator对象和location对象。
3.Vue 中使用
在 Vue 中使用 Web Worker 略有不同,因为 Webpack、 Vite 等构建工具会对静态资源做处理,对于 Web Worker 而言,需要告知构建工具如何处理 .js 文件的 Worker。
这里以 Vite 为例,分别支持以下两种方式创建 Web Worker。
使用查询后缀导入
语法:
js
import MyWorker from './worker?worker'
const worker = new MyWorker()vue
<script setup>
import FibWorker from './workers/fib_worker?worker'
const workerMap = {};
function clickHandler(boxId) {
console.log('boxId', boxId);
let worker = workerMap[boxId];
if (!worker) {
worker = new FibWorker();
workerMap[boxId] = worker;
worker.onmessage = (event) => {
console.log('result', event.data);
const boxEl = document.getElementById(boxId);
const inputEl = boxEl.getElementsByTagName('input')[0];
const number = inputEl.value;
const spanEl = boxEl.getElementsByTagName('span')[0];
spanEl.innerHTML = `${number} fib result is ${event.data}`;
}
}
const boxEl = document.getElementById(boxId);
const inputEl = boxEl.getElementsByTagName('input')[0];
const number = inputEl.value;
worker.postMessage(number);
}
</script>使用构造函数导入
语法:
js
const worker = new Worker(new URL('./worker.js', import.meta.url))
import MyWorker from './worker?worker'js
const worker = new MyWorker()vue
<script setup>
const workerMap = {};
function clickHandler(boxId) {
console.log('boxId', boxId);
let worker = workerMap[boxId];
if (!worker) {
worker = new Worker(new URL('./workers/fib_worker.js', import.meta.url))
workerMap[boxId] = worker;
worker.onmessage = (event) => {
console.log('result', event.data);
const boxEl = document.getElementById(boxId);
const inputEl = boxEl.getElementsByTagName('input')[0];
const number = inputEl.value;
const spanEl = boxEl.getElementsByTagName('span')[0];
spanEl.innerHTML = `${number} fib result is ${event.data}`;
}
}
const boxEl = document.getElementById(boxId);
const inputEl = boxEl.getElementsByTagName('input')[0];
const number = inputEl.value;
worker.postMessage(number);
}
</script>