一、什么是 Web Worker?
Web Worker 是 HTML5 引入的 JavaScript 多线程解决方案,允许主线程(UI 线程)创建后台线程(Worker 线程),在不阻塞主线程的情况下执行耗时操作(如复杂计算、大数据处理等),从而避免页面卡顿,提升用户体验。
JavaScript 本质是单线程语言(同一时间只能执行一个任务),Web Worker 突破了这一限制,使 CPU 密集型任务可以在后台并行处理。
二、核心特性
-
线程隔离
主线程与 Worker 线程完全隔离,拥有各自的全局作用域和内存空间,不能直接共享数据。 -
通信机制
通过postMessage
发送消息,onmessage
接收消息,数据传递采用结构化克隆算法(深拷贝,非共享),支持大部分数据类型(对象、数组、基本类型等),但不支持函数、DOM 节点等。特殊场景下可使用
Transferable Objects
(如 ArrayBuffer)实现数据 "转移"(转移后原线程无法再访问该数据),避免拷贝开销。 -
受限的全局作用域
Worker 线程中不能访问:- DOM 节点(如
document
、window
) window
对象的大部分属性(如alert
、localStorage
)- 主线程的全局变量或函数
可访问的 API:
setTimeout
、fetch
、XMLHttpRequest
、navigator
、location
(只读)等。 - DOM 节点(如
-
生命周期
由主线程创建(new Worker(scriptUrl)
),可通过terminate()
强制终止(主线程调用)或self.close()
自行关闭。
三、使用场景
- 大数据处理(如表格数据排序、过滤、统计)
- 复杂数学计算(如科学计算、图形学算法)
- 加密 / 解密、数据压缩等 CPU 密集型任务
- 后台定时任务(如周期性数据同步)
四、基本使用示例
1. 主线程(main.js)
// 创建 Worker 实例(脚本路径需同源)
const worker = new Worker('worker.js');
// 发送数据到 Worker
worker.postMessage({ type: 'calc', data: 100 });
// 接收 Worker 返回的结果
worker.onmessage = (e) => {
console.log('计算结果:', e.data);
};
// 监听错误
worker.onerror = (err) => {
console.error(`Worker 错误:${err.message}`);
worker.terminate(); // 出错后终止
};
// 页面关闭时终止 Worker
window.addEventListener('beforeunload', () => {
worker.terminate();
});
2. Worker 线程(worker.js)
// 接收主线程消息
self.onmessage = (e) => {
const { type, data } = e.data;
if (type === 'calc') {
// 执行耗时计算(示例:计算斐波那契数列)
const result = fibonacci(data);
// 发送结果回主线程
self.postMessage(result);
// 完成后自行关闭(可选)
self.close();
}
};
// 耗时计算函数
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
Web Worker 在 Vue2 中的应用
一、核心思路
在 Vue2 组件中使用 Web Worker 需结合组件生命周期管理 Worker 实例,确保:
- 组件创建时初始化 Worker
- 组件销毁时终止 Worker(避免内存泄漏)
- 通过消息机制与组件数据联动
二、具体实现步骤
1. 创建 Worker 脚本
在 public
目录下创建 worker.js
(需放在 public 下,避免打包时被编译):
// public/worker.js
self.onmessage = (e) => {
const { task, payload } = e.data;
// 根据任务类型处理
switch (task) {
case 'heavy-calc':
const result = heavyCalculation(payload);
self.postMessage({ status: 'done', result });
break;
default:
self.postMessage({ status: 'error', message: '未知任务' });
}
};
// 模拟耗时计算(如处理10万条数据)
function heavyCalculation(data) {
return data.map(item => {
// 复杂逻辑(示例:平方+开方)
return Math.sqrt(item * item * 1.5);
});
}
2. 在 Vue 组件中使用
<template>
<div class="worker-demo">
<button @click="startCalc">开始计算</button>
<p v-if="loading">计算中...</p>
<p v-if="result">结果长度:{{ result.length }}</p>
<p v-if="error" class="error">{{ error }}</p>
</div>
</template>
<script>
export default {
data() {
return {
worker: null, // Worker 实例
loading: false,
result: null,
error: ''
};
},
created() {
// 初始化 Worker(组件创建时)
this.initWorker();
},
beforeDestroy() {
// 组件销毁时终止 Worker
this.terminateWorker();
},
methods: {
initWorker() {
// 注意路径:public 目录下的文件需用绝对路径
this.worker = new Worker('/worker.js');
// 接收 Worker 消息
this.worker.onmessage = (e) => {
this.loading = false;
if (e.data.status === 'done') {
this.result = e.data.result;
} else {
this.error = e.data.message;
}
};
// 监听错误
this.worker.onerror = (err) => {
this.loading = false;
this.error = `计算错误:${err.message}`;
this.terminateWorker(); // 出错后销毁
};
},
terminateWorker() {
if (this.worker) {
this.worker.terminate();
this.worker = null;
}
},
startCalc() {
this.loading = true;
this.result = null;
this.error = '';
// 生成10万条测试数据
const testData = Array.from({ length: 100000 }, () => Math.random() * 1000);
// 发送任务到 Worker
this.worker.postMessage({
task: 'heavy-calc',
payload: testData
});
}
}
};
</script>
<style scoped>
.error { color: red; }
</style>
三、注意事项
-
Worker 脚本路径问题
- 开发环境:需放在
public
目录下,通过绝对路径(/worker.js
)访问(避免相对路径导致的 404)。 - 生产环境:确保打包后
worker.js
与页面在同一域名下(同源限制)。
- 开发环境:需放在
-
数据传递限制
- 不能传递 Vue 实例、
this
、DOM 节点等(结构化克隆算法不支持)。 - 大数据传递建议用
Transferable Objects
(如worker.postMessage(buffer, [buffer])
),但转移后原数据不可用。
- 不能传递 Vue 实例、
-
Vuex 状态同步
Worker 中不能直接访问 Vuex,需通过主线程中转:// Worker 回传结果后,在主线程更新 Vuex this.worker.onmessage = (e) => { this.$store.dispatch('updateResult', e.data.result); };
-
兼容性
现代浏览器均支持(IE 10+),可通过if (window.Worker)
判断是否支持。 -
性能优化
- 避免频繁创建 / 销毁 Worker(可复用实例)。
- 拆分大任务为小任务,分批处理(避免 Worker 长时间占用线程)。
四、封装为 Vue 插件(进阶)
为简化多个组件使用 Worker,可封装为插件:
// plugins/workerPlugin.js
export default {
install(Vue) {
Vue.prototype.$createWorker = (scriptUrl) => {
const worker = new Worker(scriptUrl);
// 封装通信方法
const send = (data) => worker.postMessage(data);
const onMessage = (callback) => {
worker.onmessage = (e) => callback(e.data);
};
const terminate = () => worker.terminate();
return { send, onMessage, terminate };
};
}
};
在 main.js
中注册:
import workerPlugin from './plugins/workerPlugin';
Vue.use(workerPlugin);
组件中使用:
this.worker = this.$createWorker('/worker.js');
this.worker.send({ task: 'calc', data: 100 });
this.worker.onMessage((result) => {
console.log('结果:', result);
});
Web Worker 是解决 JavaScript 单线程瓶颈的重要方案,尤其适合处理 CPU 密集型任务。在 Vue2 中使用时,需注意生命周期管理、路径配置和数据传递限制,通过合理封装可进一步提升开发效率。