HTML5 Web Workers
JavaScript 默认运行在浏览器的"主线程"上,一旦执行耗时任务(大循环、图片处理),页面就会卡死无法点击。Web Workers 让脚本在后台线程运行,不阻塞界面,适合做计算密集型任务。学习它是优化网页流畅度的关键一步。
为什么需要 Worker
看下面这段代码:点击按钮后主线程忙 5 秒,期间页面任何交互都没反应。
function heavy() {
var end = Date.now() + 5000;
while (Date.now() < end) { /* 空转 5 秒 */ }
alert("忙完了");
}
把这类计算放进 Worker,主线程立刻恢复响应,用户可继续操作页面。
创建与使用 Worker
Worker 运行在一个独立 JS 文件里。主线程用 new Worker("文件名") 创建,通过 postMessage() 发数据、onmessage 收结果;terminate() 立即终止。
<p id="r">计算中……</p>
<script>
var w = new Worker("calc.js"); // 启动后台线程
w.onmessage = function (e) { // 接收计算结果
document.getElementById("r").innerHTML = "结果:" + e.data;
};
w.postMessage(1000000); // 把任务参数发过去
</script>
Worker 文件(calc.js)
Worker 内部用 onmessage 收任务、postMessage 回传结果,不能使用 document、window 等 DOM API。
// calc.js —— Worker 线程中执行
onmessage = function (e) {
var n = e.data, sum = 0;
for (var i = 1; i <= n; i++) { sum += i; }
postMessage(sum); // 把结果送回主线程
};
在浏览器中显示为:稍等片刻页面显示"结果:500000500000",期间页面始终可以点击、滚动,不卡顿。
一次一用:onmessage 与对象实例
- 需要多次计算可重复
w.postMessage(),每次都会触发 Worker 的 onmessage。 - 计算完用
w.terminate()关闭线程,释放内存。 - 主线程想主动给 Worker 下多个不同类型任务时,可约定消息里带 type 字段做分发。
Worker 的局限
Worker 线程不能访问 DOM(document、window、parent),也不能用 alert/confirm;它和主线程只能靠 postMessage 传递数据(字符串或可结构化克隆的对象)。同源策略同样适用,且用 file:// 直接打开页面时部分浏览器会禁用 Worker,建议用本地服务器测试。
易错点
① 忘记处理 onerror,Worker 出错时静默失败——加上 w.onerror 输出错误信息便于排查;② 传大对象每次都是复制/克隆,频繁传大数据会抵消性能收益;③ 不是所有任务都值得开线程,简单任务的开销可能更大;④ 老浏览器不支持时先做特性检测:if (typeof Worker !== "undefined")。
小结:Web Workers 把重计算放到后台线程,通过 postMessage/onmessage 与主线程通信,能让页面在大任务下保持流畅;记住它不能碰 DOM、要同源并用服务器环境测试。