vite
中使用web worker
1.web worker
介绍
JavaScript
是单线程模型,所有任务只能在一个线程上完成,前面的事情没有完毕,后面的事情要等待前面的事情处理完毕后才能执行。但随着电脑计算能力的增强,尤其是多核CPU
的出现,单线程已无法充分发挥计算机的计算能力。
web worker
可为 JavaScript
创造多线程环境,允许主线程创建worker
线程,可将一些计算密集型或高延迟的任务分配给worker
。worker
线程在后台运行,与主线程互不干扰。等到 worker
线程完成计算任务,再把结果返回给主线程。如此,可有效提高应用性能。
2.原生环境使用web worker
**原生环境使用`worker`示例:**
下面代码功能,主线程发送两个数字给worker,worker求两数字之和,再将结果发送回主线程
`./main.js` `(main thread)`
// 兼容性判断
if (window.Worker) {
// 1.创建一个worker
const myWorker = new Worker('worker.js');
// 2.worker消息监听
myWorker.onmessage = e => {
const data = e.data;
console.log(`Message received from worker, sum: ${data.sum}`);
};
// 3.worker异常监听
myWorker.onerror = e => {
console.error(e);
};
// 4.向worker线程发送数据,注意,只能传递一个参数,如有多个参数,可以包装成Object
myWorker.postMessage({ a: 1, b: 2 });
// 5.当离开页面的时候,或者需要结束worker时(比如任务完成时),
// 可以结束Worker线程,不必占用资源
// myworker.terminate();
} else {
// 不支持web worker
console.log("Your browser doesn't support web workers.");
}
`./worker.js` `(worker thread)`
// 1.监听主线程消息
self.onmessage = e => {
// 2.接收来自主线程发送过来的数据
const data = e.data;
console.log(`Message received from main thread, a: ${data.a}, b: ${data.b}`);
const sum = data.a + data.b;
// 3.将结果发送给主线程
self.postMessage({ sum });
};
// 4.在worke 线程中也可以监听错误信息
self.onerror = e => {
console.log(e);
};
// 5.worker线程也可以调用close结束worker线程
// self.close();
一些API
说明:
-
主线程可调用原生
API
Worker()
函数,新建一个worker
Worker()
构造函数的参数是一个脚本文件,该文件就是worker
线程所要执行的任务。var worker = new Worker('work.js');
-
然后,主线程可调用
worker.postMessage()
方法,向worker
发消息worker.postMessage('Hello World');
-
接着,主线程通过
worker.onmessage
定义监听函数,接收worker
发回来的消息worker.onmessage = (e) => { console.log('Received message: ' + e.data); }
-
最后,
worker
完成任务以后,主线程就可以把它关掉worker.terminate();
web worker
注意点:
-
同源限制
worker
脚本文件必须与主线程文件同源。 -
API
限制worker
线程的全局对象与主线程不一样,无法读取网页的DOM
对象,也无法使用document
、window
、parent
这些对象。但是可以使用navigator
对象和location
对象。也可以使用XMLHttpRequest
对象发出AJAX
请求。 -
通信
worker
线程和主线程不在同一个上下文环境,不能共用变量,如果要交互信息,必须通过postMessage
完成。
3.vite
中使用web worker
vite
也支持web worker
,不过其中存在一些陷阱,官方提供了两种使用web worker的方式,官方文档传送门:
-
带有查询后缀的导入
import Worker from './worker.js?worker' const worker = new Worker()
此方式在
vite2.x
版本下,可在测试环境和正式环境正常使用(亲测) -
通过构造器导入(官方推荐方式)
const worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module', })
此方式在
vite2.x
版本下,只能在测试环境正常工作,无法用于生产环境(亲测)
在vite
中使用的完整示例,依然是实现求和功能:
main.js
(也可以是.vue
文件中的任意主线程脚本)
import myWorker from './myWorker?worker&inline';
let worker = null;
if (window.Worker) {
worker = new myWorker();
worker.onmessage = e => {
const data = e.data;
console.log(data.sum);
};
worker.onerror = e => console.error(e);
}
if (worker) {
worker.postMessage({ a: 1, b: 2 });
}
myWorker.js
(需要处于src
目录下,如果处于public
目录将无法使用,亲测)
self.onmessage = e => {
const data = e.data;
const sum = data.a + data.b;
self.postMessage({ sum });
};
self.onerror = e => console.log(e);