useWorker 是一个轻量、生产就绪的 Vue 3 组合式 API 封装,支持响应式 Worker 状态管理、Promise 化通信、自动清理、类型安全及内联 Worker;核心提供 init、post、terminate 等方法,并在组件卸载时自动终止 Worker 防止内存泄漏。

Vue 3 的组合式 API 非常适合封装可复用的逻辑,Worker 状态管理正是典型场景:需处理创建、通信、错误、终止等生命周期,同时保持响应式。下面是一个轻量、实用、生产就绪的 useWorker 插件实现思路与代码。
核心设计原则
不侵入全局、不依赖构建工具(支持直接 script 引入)、自动清理、类型安全(TypeScript 友好)、支持 Promise 化消息收发。
- Worker 实例按需创建,避免重复初始化
- 消息通信双向响应式:发送即 resolve,接收自动触发更新
- 错误统一捕获并暴露为 ref,便于 UI 层反馈
- 组件卸载时自动 terminate,防止内存泄漏
- 支持内联字符串 Worker(兼容无服务环境)或 URL 构造
基础 useWorker 组合函数(TypeScript + 响应式)
以下为可直接使用的组合函数,无需插件注册,开箱即用:
import { ref, onUnmounted, onDeactivated } from 'vue'
export function useWorker<T extends Record<string, any>, R extends Record<string, any>>(
workerSrc: string | (() => string),
options: { name?: string; type?: 'classic' | 'module' } = {}
) {
const status = ref<'idle' | 'running' | 'terminated' | 'error'>('idle')
const error = ref<Error | null>(null)
const lastMessage = ref<R | null>(null)
const worker = ref<Worker | null>(null)
// 创建 Worker(支持内联或 URL)
const init = () => {
if (worker.value) return
try {
const code = typeof workerSrc === 'function' ? workerSrc() : workerSrc
const blob = new Blob([code], { type: 'application/javascript' })
const url = URL.createObjectURL(blob)
worker.value = new Worker(url, { ...options, name: options.name || 'vue-worker' })
status.value = 'running'
error.value = null
// 消息接收
worker.value.onmessage = (e: MessageEvent) => {
lastMessage.value = e.data as R
}
// 错误捕获
worker.value.onerror = (e: ErrorEvent) => {
error.value = e.error || new Error(e.message)
status.value = 'error'
}
} catch (e) {
error.value = e instanceof Error ? e : new Error(String(e))
status.value = 'error'
}
}
// 发送消息(返回 Promise,自动 resolve 收到的 reply)
const post = async (data: T, timeout = 10_000): Promise<R> => {
if (!worker.value) throw new Error('Worker not initialized')
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error('Worker message timeout'))
}, timeout)
const handleReply = (e: MessageEvent) => {
clearTimeout(timer)
worker.value?.removeEventListener('message', handleReply)
resolve(e.data as R)
}
worker.value.addEventListener('message', handleReply)
worker.value.postMessage(data)
})
}
// 主动终止
const terminate = () => {
if (worker.value) {
worker.value.terminate()
URL.revokeObjectURL(worker.value?.scriptURL || '')
worker.value = null
status.value = 'terminated'
lastMessage.value = null
}
}
// 自动清理(组件卸载/失活时)
onUnmounted(terminate)
onDeactivated(terminate)
return {
worker,
status,
error,
lastMessage,
init,
post,
terminate
}
}
使用示例:图像模糊计算 Worker
在组件中调用:
立即学习“前端免费学习笔记(深入)”;
<script setup lang="ts">
import { useWorker } from './useWorker'
// 内联 Worker 逻辑(也可传入 URL)
const imageWorkerCode = `
self.onmessage = async ({ data }) => {
const { imageData, radius } = data
// 模拟耗时模糊处理(实际可用 wasm 或 canvas)
await new Promise(r => setTimeout(r, 800))
self.postMessage({ result: 'blurred_' + Date.now(), processed: true })
}
`
const { status, error, lastMessage, init, post } = useWorker(imageWorkerCode)
const startBlur = async () => {
init()
try {
const res = await post({ imageData: {}, radius: 5 })
console.log('Worker result:', res) // { result: "...", processed: true }
} catch (e) {
console.error('Worker failed:', e)
}
}
</script>
<template>
<button @click="startBlur" :disabled="status === 'running'">
{{ status === 'running' ? 'Processing...' : 'Blur Image' }}
</button>
<div v-if="error">❌ {{ error.message }}</div>
<div v-if="lastMessage">✅ {{ JSON.stringify(lastMessage) }}</div>
</template>
进阶增强建议
如需更高可靠性或复杂场景,可扩展以下能力:
- 多消息队列:用 Map 存储 pending promise,支持并发多次 post 并区分响应
- 自动重连:Worker 异常终止后,提供 retry 选项和指数退避
-
共享 Worker 支持:通过
new SharedWorker()实现跨 tab 复用(注意兼容性) -
Comlink 集成:用
comlink替代手动 postMessage,实现函数式调用(worker.doSomething().then(...)) -
Vue 插件封装:挂载为
app.use(WorkerPlugin),提供全局 $worker 工厂方法
这个实现不依赖任何第三方库,仅用 Vue 3 组合式 API 和原生 Worker,兼顾简洁性与工程健壮性。关键是把状态、副作用、清理逻辑全部收敛在组合函数内,让业务组件专注使用,而非管理底层细节。



















