最近在优化公司的一个项目,使用的就是web worker去优化,做了那些优化,一个是状态的优化,(通信的状态实时更新,以前的做法是做个定时任务实时获取它的状态,然后让它在页面渲染,这样就会造成了,一个是定时任务,实时获取,一个是一直在不断的渲染,虽然肉眼看不出什么,但是这样会造成一个主进程的负担非常大,然后我就引用了web worker开一个进程给它,定时去获取,然后在做判断是否与前面的状态是否一致,一致不传入主进程,不一致传入,然后这样就可以页面的明显的比较丝滑了)还有一个就是做一个计算,涉及到了比较复杂的数据,然后也是在web worker计算好了在传入主线程。最后用来做文件的下载,因为我们的文件涉及到了视频的下载,有些视频几个G的下载,那就是用了这个来处理。这篇文章呢,本来打算自己写的,然后做总结,然后自己比较懒,发现GPT写的比我还全面。当然我也参考了其它文章来看是否写的正常,对比MDN.
Web Worker 是一项 HTML5 标准中的特性,可以在 Web 页面中创建多个 JavaScript 线程,从而实现多线程并行执行代码的效果。它是为了解决 JavaScript 在单线程下的并发执行问题而出现的。使用 Web Worker 可以使 UI 界面保持流畅和响应性,并有效地利用计算机的硬件资源,提高 Web 应用程序的性能和响应速度。
Web Worker 主要有两种类型:Dedicated Worker 和 Shared Worker。Dedicated Worker 是指只与一个页面相关联的 Worker,而 Shared Worker 则是可以被多个页面共享的 Worker。Worker 可以操作独立的数据副本,这些数据副本在线程之间通信时不会互相干扰,并可以使用 postMessage() 方法进行相互通信。
下面详细介绍 Web Worker 的相关知识点:
Web Worker 最重要的作用是将一部分代码运行在另一个线程中,用以减轻主线程负荷,以达到提高网页性能的目的。
使用 Worker API 来创建一个后台工作者线程,语法如下:
// 创建一个 Worker 线程
var myWorker = new Worker('worker.js');
其中,worker.js 为后台线程所要执行的 JavaScript 文件。
Web Worker 分为两种类型:Dedicated Worker 和 Shared Worker。Dedicated Worker 是指只与一个页面相关联的 Worker,而 Shared Worker 则是可以被多个页面共享的 Worker。
Dedicated Worker 的创建方式比较简单,而 Shared Worker 的使用方法则比较复杂。例如,当多个页面同时使用同一个 Shared Worker 时,它们在访问该 Worker 时必须保证具有相同的域名和端口号。
Dedicated Worker 和主线程之间可以通过 postMessage() 方法来传递消息,在 Dedicated Worker 中可以使用 self 属性代替 this,其中 self.postMessage() 用于向主线程发送消息。
主线程接收后台 Worker 发送过来的信息,可以通过 onmessage 事件进行处理,代码如下:
// 主线程代码
// 创建 Worker
var myWorker = new Worker('worker.js');
// 接收来自 Worker 的消息并进行处理
myWorker.onmessage = function(event) {
console.log('Received message from worker:', event.data);
};
由于 JavaScript 实现不支持锁,因此 Web Worker 的实现也没有锁概念。但可以借助 MessageChannel API 来模拟锁,即将信道分成互斥的“写入键”和“读取键”,从而控制对数据结构的访问。
Web Worker 在实际使用时也存在一些限制和局限性,例如:
Web Worker API 允许在主线程和后台线程之间交换二进制数据,以及共享 ArrayBuffer 和 MessagePort 对象。可以使用 postMessage() 方法发送 ArrayBuffers、TypedArrays 和 DataViews。 示例代码如下:
// 计算行列式
function determinant(matrix) {
var length = matrix.length;
if (length === 2) {
return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
} else {
var result = 0;
var cofactor = 1;
for (var i = 0; i < length; i++) {
var minor = [];
for (var j = 1; j < length; j++) {
minor.push(matrix[j].slice(0, i).concat(matrix[j].slice(i + 1)));
}
result += cofactor * matrix[0][i] * determinant(minor);
cofactor = -cofactor;
}
return result;
}
}
// 主线程
var myWorker = new Worker('worker.js');
myWorker.onmessage = function(event) {
console.log('Received worker message:', event.data);
};
// 创建 ArrayBufer,这里是一个 4x4 的矩阵
var buffer = new ArrayBuffer(64);
var view = new Int32Array(buffer);
for (var i = 0; i < 16; i++) {
view[i] = i;
}
// 向 worker 发送 ArrayBuffer
myWorker.postMessage(buffer, [buffer]);
错误处理
在 Web Worker 中,当代码执行出现错误时,会抛出一个相应的异常。Worker 可以通过将错误对象传递给主线程来报告错误。示例代码如下:
// 后台 Worker 代码示例,计算阶乘
self.onmessage = function(event) {
var n = event.data;
if (n < 0) {
self.postMessage('Error: argument must be non-negative');
} else {
var result = 1;
for (var i = 2; i <= n; i++) {
result *= i;
}
self.postMessage(result);
}
};
使用 Web Worker 进行性能优化时,可以考虑以下几点:
Web Worker 之间通过消息传递进行通信。可以使用 postMessage() 和 onmessage 属性在主线程和 Worker 之间发送和接收消息。示例代码如下:
// 主线程
var myWorker = new Worker('worker.js');
myWorker.onmessage = function(event) {
console.log('Received worker message:', event.data);
};
myWorker.postMessage(42);
// 后台 Worker 代码示例
self.onmessage = function(event) {
console.log('Received message from main thread:', event.data);
self.postMessage('Hello, main thread!');
};
可以使用 terminate() 方法终止 Worker 线程。示例代码如下:
// 主线程
var myWorker = new Worker('worker.js');
myWorker.postMessage(42);
// 等待 2 秒后终止 Worker 线程
setTimeout(function() {
myWorker.terminate();
console.log('Worker terminated.');
}, 2000);
// 后台 Worker 代码示例
self.onmessage = function(event) {
console.log('Received message from main thread:', event.data);
};
除了上面提到的方法和属性,Web Worker 还提供了一些其他的 API,包括:
Worker 线程执行的代码必须是线程安全的,因为它们在多个线程中同时运行。具体来说,Worker 线程不能访问主线程的 DOM、BOM 或 JavaScript 对象,而是操作自己的局部变量和引入的脚本库。由于共享内存的特性,如果多个 Worker 同时读写同一个共享变量,可能会导致数据竞争和不可预期的结果。
SharedArrayBuffer 是 HTML5 的新增特性,可以在多个 Worker 之间共享内存。与普通数组不同,SharedArrayBuffer 的操作是原子性的,能够保证多个线程同时读写 SharedArrayBuffer 不会出现竞争和冲突。
使用 SharedArrayBuffer 需要注意以下问题:
Web Worker 可以用于许多场景,这里举几个实际应用的例子:
Web Worker 主要有以下几个限制:
Web Worker 是 HTML5 中新增的特性,需要浏览器支持。目前绝大多数主流浏览器都支持 Web Worker,但是还有一些老版本的浏览器可能不支持。
为了解决兼容性问题,可以使用 Modernizr 库,检测当前浏览器是否支持 Web Worker,并提供相应的替代方案。
由于 Worker 线程不能使用 alert()、console.log() 和调试工具,因此在调试 Web Worker 时可能比较困难。下面是一些调试技巧:
Web Worker 还可以用于许多其他情况,例如:
总之,Web Worker 是一个非常强大且有用的工具,可以大幅提高 JavaScript 程序的性能和可维护性。但是一定要注意避免共享内存等问题,保证程序的正确性和安全性。
对比文章:(Exploring The Potential Of Web Workers For Multithreading On The Web)[https://www.smashingmagazine.com/2023/04/potential-web-workers-multithreading-web]
当然国内也有人去进行了一个翻译:译文
web worker使用:这篇第二种方式是有点问题的,不支持es6以上的语法,所以还是推荐使用worker-load
这篇:融会贯通
github也有人进行了一个简单的封装可以看看他:gitHub web worker