Web Worker 热更新本质是模块级替换与状态可控迁移,通过 ES 模块 + 动态 import() 替代 importScripts,配合消息协议接管状态、Service Worker 协同缓存更新及资源安全回收实现。

Web Worker 的热更新与动态加载,本质是让后台线程能响应代码变更、不重启即可切换逻辑,同时避免主线程阻塞和资源冗余。核心不在“重载整个 Worker”,而在于模块级替换与状态可控迁移。
用动态 import() 替代 importScripts
importScripts 是同步阻塞式加载,无法卸载或更新,且污染全局作用域。现代方案应优先使用 ES 模块 Worker + 动态 import():
- Worker 文件声明为
type="module",支持import()按需加载核心逻辑(如 ffmpeg-core、解析器、索引引擎) - 每次热更新时,不再调用
importScripts,而是执行await import(newURL + '?t=' + Date.now()),强制绕过缓存获取新版 - 旧模块引用可被 GC 回收——只要不再持有其导出对象的引用(例如清空全局变量、关闭监听器、释放 ArrayBuffer)
基于消息协议的状态接管机制
Worker 本身不可“热重启”,但可通过主线程发送指令,让其主动卸载旧逻辑、加载新模块并恢复上下文:
- 主线程发消息:
{ type: 'reload-core', url: '/assets/core/v2.4/ffmpeg-core.js' } - Worker 收到后:停止当前任务、销毁旧 ffmpeg 实例、
await import(url)加载新版、调用createFFmpegCore()初始化 - 关键点:所有状态(如进度、队列、临时内存)需在 reload 前序列化传回主线程,加载完成后由主线程重新注入
结合 Service Worker 实现资源秒级生效
仅靠 Worker 内部 reload 不够——若 core 脚本本身被 Service Worker 缓存,用户可能仍拿到旧版本。需协同协商缓存:
- Service Worker 在 fetch 中对 core 脚本发起带
If-None-Match的条件请求 - 服务端返回 304 表示未变,Worker 继续用当前模块;返回 200 则自动更新缓存,并通知 Worker 触发 reload
- 这样主线程或 Worker 发起的 import() 请求,总能拿到服务端最新版,无需手动清缓存或强制刷新
资源隔离与安全回收
热更新容易引发内存泄漏,尤其涉及 WebAssembly 实例、SharedArrayBuffer 或大量 ArrayBuffer:
- 每次加载新模块前,显式调用
ffmpeg.FFmpegModule?.onRuntimeInitialized?.()类清理钩子(如有) - 用
transferable传递大数组,避免复制;更新后主动postMessage({ type: 'free', id })通知主线程释放对应 buffer - Worker 内部维护模块引用计数,当某个 core 版本无任何任务在运行时,延迟 1 秒后执行
delete window['FFmpegCore_v2_3']等清理动作










