Skip to content

Worker 生命周期与消息协议 ​

Worker 把计算移出主线程,但它不会共享页面的 DOM 或普通 JavaScript 堆。学习重点是建立消息协议、处理错误,并在页面离开时终止资源。

最小实验:可运行的模块 Worker ​

在同一目录创建 index.html、main.js、worker.js,用 npx serve . 或其他静态服务器打开 index.html(不能直接使用 file://)。

worker.js:

js
self.addEventListener('message', ({ data }) => {
  if (data.type !== 'square') return
  const result = data.value * data.value
  self.postMessage({ type: 'result', requestId: data.requestId, result })
})

main.js:

js
const worker = new Worker('./worker.js', { type: 'module' })
const requestId = crypto.randomUUID()
worker.addEventListener('message', ({ data }) => {
  if (data.requestId === requestId) console.log('result', data.result)
})
worker.addEventListener('error', (event) => console.error('worker error', event.message))
worker.postMessage({ type: 'square', requestId, value: 7 })

window.addEventListener('pagehide', () => worker.terminate(), { once: true })

预期控制台先输出 result 49。把 value 改成字符串,或把 worker.js 中的 result 改成不存在的变量,分别观察协议数据错误和 error 事件。刷新页面后,旧 Worker 不应继续输出日志。

机制与边界 ​

postMessage 传递的是结构化克隆后的值;不能传递 DOM 节点,也不能直接读取页面变量。每条消息应有类型和请求 ID,避免多个请求返回时无法匹配。terminate() 是立即终止;需要可协作取消时,应额外设计 cancel 消息并让 Worker 定期检查。

练习 ​

  1. 为协议增加 cancel 消息,让一个循环计算在收到取消后返回 { type: 'cancelled' }。
  2. 故意让 Worker 抛错,说明页面端如何区分协议错误和脚本加载错误。
  3. 删除 pagehide 清理并通过刷新观察旧资源,写出为什么单页应用切换路由时也需要显式终止。

查看本节答案

下一步 ​

继续学习 structured clone 与 Transferable,再回到本节比较复制和转移的所有权变化。

用心记录每一步成长