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、要同源并用服务器环境测试。

笔记加载中…