作者:刮刮乐打工仔
https://juejin.cn/post/7439918857492660259
前提:什么是线程?🚀
线程(英语:thread)是操作系统[1]能够进行运算调度[2]的最小单位。它被包含在进程[3]之中,是进程[4]中的实际运作单位。一条线程指的是进程[5]中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
线程是独立调度和分派的基本单位。
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符[6]和信号处理[7]等等。但同一进程中的多个线程有各自的调用栈[8](call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
JavaScript单线程
JavaScript设计成单线程目的:为了防止多个线程同时操作DOM,带来渲染冲突问题。
但是遇见大量计算会使页面卡顿,用户体验不佳
就引出本篇的主题Web Worker
🚀Web Worker🚀
Web Worker
允许我们在 js 主线程之外开辟新的 Worker 线程。 因为是独立的线程,Worker 线程与 js 主线程能够同时运行,互不阻塞。 如果有大量运算任务时,可以把运算任务交给 Worker 线程去处理,当 Worker 线程计算完成,再把结果返回给 js 主线程。
js主线程只用专注处理业务逻辑,Worker处理大量复杂计算,从而减少了主线程阻塞 时间,提高运行效率和提升用户体验。
Web Worker用法
const worker = new Worker(path, options);
path
js脚本的路径地址(遵守同源策略),否则会抛出SECURITY_ERR
类型错误
type
worker 类型。该值可以是 classic
或 module
。 默认值 classic
credentials
worker凭证。该值可以是 omit
, same-origin
,或 include
。默认值 omit
(不要求凭证)
主线程与Worker参数之间参数传递
index.html
const myWorker = new Worker('/worker.js');
myWorker.addEventListener('message', e => {
console.log(e.data);
});
myWorker.postMessage('这里是主线程');
worker.js
// self是worker的全局对象,它继承了WorkerGlobalScope的属性和方法
self.addEventListener('message', e => {
console.log(e.data);
self.postMessage('这里是worker线程');
});
控制台输出结果
线程监听
index.html
const myWorker = new Worker('/worker.js');
myWorker.addEventListener('error', err => {
console.log(err.message);
});
myWorker.addEventListener('messageerror', err => {
console.log(err.message)
});
work.js
self.addEventListener('error', err => {
console.log(err.message);
});
self.addEventListener('messageerror', err => {
console.log(err.message);
});
线程关闭
index.html
const myWorker = new Worker('/worker.js');
myWorker.terminate(); // 关闭worker
worker.js
self.close();
线程内部引用其它文件
worker 线程中利用 importScripts()
方法加载js文件,此方法加载的js文件不受同源策略约束
utils.js
const fn = ()=>{
console.log("hello, world")
}
worker.js
// 使用方法:importScripts(path1, path2, ...);
importScripts('./utils.js
// 直接使用
fn()
如果你的utils是ESModule, 生成Worker实例的时候,type指定类型为module, 这个时候你的word.js需把顶级对象self暴露出去
index.html
const worker = new Worker('/worker.js', {
type: 'module' // 指定 worker.js 的类型
});
worker.js
...
export default self; // 只需把顶级对象self暴露出去即可
传参注意事项
🚀SharedWorker🚀
SharedWorker
接口代表一种特定类型的 worker,可以从几个浏览上下文中访问,例如几个窗口、iframe 或其他 worker。它们实现一个不同于普通 worker 的接口,具有不同的全局作用域,`SharedWorkerGlobalScope`[9] 。
实现多页面通信
a.html
const worker = new SharedWorker('calculator.js');
worker.port.onmessage = function(event) {
console.log(event.data); // 接收SharedWorker返回的结果
};
worker.port.postMessage({ type: 'add', operands: [2, 3] }); // 向SharedWorker发送消息
b.html
const worker = new SharedWorker('calculator.js');
worker.port.onmessage = function(event) {
console.log(event.data); // 接收SharedWorker返回的结果
};
worker.port.postMessage({ type: 'multiply', operands: [4, 5] }); // 向SharedWorker发送消息
calculator.js
const ports = [];
self.onconnect = function(event) {
const port = event.ports[0];
ports.push(port);
port.onmessage = function(event) {
const message = event.data;
const result = calculate(message.type, message.operands); // 执行计算任务
ports.forEach(port => port.postMessage(result)); // 将结果发送给所有连接的页面
};
};
function calculate(type, operands) {
if (type === 'add') {
return operands.reduce((a, b) => a + b, 0);
} elseif (type === 'multiply') {
return operands.reduce((a, b) => a * b, 1);
}
}
🚀Web Worker(性能优化)总结🚀
- 多线程处理:Web Worker 允许在独立的线程中运行 JavaScript 代码,这样可以充分利用多核处理器和提高性能。
- 避免阻塞主线程:通过将一些密集计算或长时间运行的任务放在 Web Worker 中,可以避免阻塞主线程,提高页面的响应性。
- 异步处理:Web Worker 提供了一个与主线程并行执行脚本的环境,可以处理一些异步任务,如网络请求、数据处理等,从而提高性能。
- 数据共享:Web Worker 可以通过消息传递机制与主线程通信,还可以共享数据,这样可以更高效地处理复杂的数据操作。
- 模块化设计:将复杂的任务拆分成多个模块,在不同的 Web Worker 中并行处理,可以提高代码的可维护性和性能。
- 资源加载:Web Worker 无法访问 DOM,因此在使用 Web Worker 时需要注意不能直接操作 DOM 元素,避免因此导致性能问题。
- 性能测试:在使用 Web Worker 优化性能时,需要进行性能测试和监控,以确保 Web Worker 的引入确实提高了页面性能。
该文章在 2025/1/24 11:05:05 编辑过