在浏览器里 JavaScript 本身被设计成单线程语言,初衷是为了避免多线程操作 DOM 时可能出现的复杂冲突问题。这种单线程模型有一个显著的短板:一旦遇到长时间运行的耗时任务,比如一个执行超过 50 毫秒的长任务,它就会阻塞住唯一的主线程。导致页面变得无法及时响应你的任何点击或输入,感到明显的卡顿。
Web Worker 是 HTML5 引入的浏览器多线程技术,它允许将计算密集型或长时间运行的任务从主线程中剥离出来,在后台的独立线程中运行。这样一来,主线程就能专注于处理用户交互和页面渲染,从而有效避免页面卡顿、无响应等性能问题。
常见的耗时任务有:
当数据量较小(例如少于1000条)且业务逻辑相对简单时,Web Worker的通信开销可能超过其带来的性能收益。这是因为 Web Worker 与主线程之间的通信依赖于 postMessage API,数据传输需要进行结构化克隆(Structured Clone Algorithm),这个过程会带来序列化和反序列化的开销。对于小规模数据,这种通信成本可能大于直接在主线程上执行任务的耗时,因此这种情况下建议直接在主线程处理。
下面是一个典型的使用场景示例:创建100万个随机数并进行排序,将计算密集型任务交给 Web Worker 处理,主要流程如下:
生成后台线程 sort-worker.js 文件:
// sort-worker.js
self.onmessage = function(e) {
const bigData = e.data
// 执行排序操作(不会阻塞主线程)
const sortedData = bigData.sort((a, b) => a - b)
// 处理后返回排序结果
self.postMessage(sortedData)
self.close() // 完成任务后关闭 Worker
}
生成 index.html 文件用于测试:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="sortBtn">生成100万随机数并排序</button>
<div id="result"></div>
<script>
// 创建 Web Worker 实例
const worker = new Worker('./sort-worker.js');
const btn = document.getElementById('sortBtn');
btn.addEventListener('click', () => {
// 生成100万个随机数
const largeArray = Array.from({ length: 1000000 }, () =>
Math.floor(Math.random() * 100000)
);
console.log('开始排序,主线程仍可操作...')
const startTime = performance.now()
// 发送大数据到 Worker
worker.postMessage(largeArray)
// 接收排序结果
worker.onmessage = function (e) {
const endTime = performance.now()
console.log('排序完成!前10个数据:', e.data.slice(0, 10))
console.log('排序用时:', (endTime - startTime).toFixed(2), 'ms')
document.getElementById('result').innerText =
`排序完成,共处理 ${e.data.length} 条数据,用时 ${(endTime - startTime).toFixed(2)} ms`
worker.terminate() // 释放资源
}
// 错误处理
worker.onerror = function (error) {
console.error(`Worker错误:${error.message} (行号:${error.lineno})`)
worker.terminate()
}
})
</script>
</body>
</html>
到目前为止,准备工作已经完成。需要注意的是,不能直接在浏览器中通过 file:// 协议打开 HTML 文件,因为 WebWorker 必须在 HTTPS 或 localhost 环境下才能正常注册。
接下来,我们使用 http-server 创建一个本地 Web 服务器环境:
$ npx http-server . -p 8080
然后在浏览器中访问 http://localhost:8080/index.html,点击按钮,过一会可以看到打印结果信息:
排序完成,共处理 1000000 条数据,用时 291.20 ms
↶ 返回首页 ↶