一、从大文件上传的痛点说起
场景:你正在上传一个10GB的蓝光电影,突然发现------
- 页面卡成PPT,按钮点不动!
- 上传进度条像蜗牛爬,用户想砸电脑!
- 一不小心刷新页面,全白传了......
为啥会这样?
浏览器只有一个主线程,既要渲染页面,又要处理上传任务。大文件上传时,主线程被"霸占",页面自然卡顿!
😤 用户内心OS:传个文件而已,至于让我电脑爆炸吗?
二、Web Worker:你的"多线程外挂"
1. 概念:浏览器里的"分身术"
- 主线程:负责页面渲染、事件响应(就像公司的前台,忙得不可开交)。
- Web Worker:在后台悄悄干活的新线程(像行政团队,专门处理日常琐事)。
- 核心能力 :让耗时的任务(比如大文件分片、加密)在后台运行,不阻塞主线程!
2. 作用:解放主线程,专治各种卡顿
- 大文件上传:分片、计算哈希、压缩,全丢给Worker!
- 复杂计算:比如图像处理、数据分析。
- 实时通信:WebSocket数据解析。
💡 类比:主线程是厨师,Web Worker是切菜工。厨师只管炒菜,切菜交给小弟!
三、Web Worker的优缺点
优点
- 不卡页面:主线程专心服务用户交互。
- 性能提升:多线程并行处理任务。
- 隔离环境:Worker崩溃不会影响页面。
缺点
- 不能操作DOM:Worker和主线程"物理隔离",无法直接改页面。
- 兼容性:IE11及以下不支持(但谁还用IE啊?)。
- 通信成本:主线程和Worker只能通过消息传递数据。
⚠️ 注意:别用Worker处理简单任务!创建线程本身也有开销,杀鸡别用牛刀。
四、手把手使用Web Worker
1. 创建Worker文件
新建一个upload.worker.js,专门处理上传逻辑:
ini
// upload.worker.js
self.onmessage = function(e) {
const file = e.data;
// 1. 分片处理
const chunkSize = 5 * 1024 * 1024; // 每片5MB
const chunks = [];
for (let i = 0; i < file.size; i += chunkSize) {
chunks.push(file.slice(i, i + chunkSize));
}
// 2. 告诉主线程:分片完成啦!
self.postMessage({ type: 'chunks', chunks });
};
2. 主线程调用Worker
ini
// 主页面代码
const worker = new Worker('upload.worker.js');
const fileInput = document.querySelector('input[type="file"]');
fileInput.addEventListener('change', (e) => {
const file = e.target.files[0];
worker.postMessage(file); // 把文件扔给Worker处理
});
// 接收Worker的消息
worker.onmessage = (e) => {
if (e.data.type === 'chunks') {
const chunks = e.data.chunks;
// 上传分片(这里可以用axios循环发送)
}
};
五、使用注意点 & 避坑指南
1. 同源策略
- Worker脚本必须和主页面同源,否则报错!
- 解决方案:
-
- 将Worker脚本内联为Blob(动态创建):
ini
const workerCode = `self.onmessage = function(e) { ... }`;
const blob = new Blob([workerCode], { type: 'text/javascript' });
const worker = new Worker(URL.createObjectURL(blob));
2. 资源限制
- Worker不能访问localStorage、DOM、window对象。
- 替代方案:通过postMessage传递所需数据。
3. 错误处理
- Worker内部错误不会冒泡到主线程,必须自己监听:
ini
worker.onerror = (e) => {
console.error('Worker出错啦:', e.message);
};
六、跨域问题解决
场景:Worker脚本托管在CDN(不同域名),导致加载失败。
解决方案:
- 设置CORS头:确保CDN服务器返回Access-Control-Allow-Origin: *。
- 代理转发:通过自己的服务器代理请求Worker脚本。
- 内联Worker:如上述Blob方案,彻底绕过跨域。
七、何时该用Web Worker?
- ✅ 需要处理CPU密集型任务(如大文件分片、加密)。
- ✅ 需要长时间运行且不依赖DOM的操作。
- ❌ 简单任务(比如格式化日期),用主线程就行!
实战建议:
大文件上传:用Worker分片 + 主线程控制上传队列。
配合axios的取消令牌,实现"断点续传"。
记得在页面卸载时终止Worker:worker.terminate()!
💬 作业:用Worker实现一个"计算斐波那契数列"的demo,分享你的代码!
学会Web Worker,从此告别页面卡顿,做一个优雅的前端工程师! 🎉