如何使用ES模块Worker_HTML ES Module Worker实现HTML模块化开发?
- 内容介绍
- 文章标签
- 相关推荐
本文共计861个文字,预计阅读时间需要4分钟。
普通Worker默认运行在classic模式,无法解析import语句;只有显式声明type: 'module',浏览器才会按ES模块规范加载并解析依赖。在不加选项时,不要害怕worker.js里只有一行import { foo } from './utils.js';,也会直接报错SyntaxError: Cannot use import statement outside a module。
模块 Worker 自动启用顶层 await、动态 import() 和裸 specifier 支持(需配合 importMap),但代价是:它完全禁用 importScripts() —— 所有依赖必须走标准 import 链。
new Worker() 路径必须是同源可访问的 URL
模块 Worker 对路径更敏感,常见失败原因:
-
new Worker('data:text/javascript,import%20x%20from%20"./a.js"')→ 不合法:DataURL 不支持模块解析,会报Failed to construct 'Worker': Module scripts are not supported for data URLs -
new Worker('./worker.js', { type: 'module' })→ 成功,但要求worker.js能被服务器以Content-Type: application/javascript+module或至少application/javascript返回 - 开发时用
file://协议打开 HTML → 所有模块 Worker 加载失败(CORS + 协议限制),必须起本地服务(如npx serve或 Vite)
主线程与模块 Worker 之间不能共享函数或类实例
即使双方都用 ES 模块,postMessage() 仍走结构化克隆算法,以下内容会被忽略或报错:
立即学习“前端免费学习笔记(深入)”;
-
postMessage({ fn: () => {} })→ 函数丢失,收端得到{} -
postMessage(new Date())→ 变成字符串,不是Date实例 -
postMessage(arrayBuffer, [arrayBuffer])→ 可转移,但接收方必须用e.data.buffer重新构造视图,不能直接当原 ArrayBuffer 用
正确做法是只传纯数据(Object、Array、Number、String、ArrayBuffer 等可克隆类型),复杂逻辑封装成序列化/反序列化协议,比如用 JSON.stringify() + JSON.parse() 控制字段粒度。
模块 Worker 中不能用 localStorage、document、window
这是所有 Worker 的共性,但模块 Worker 容易让人误以为“既然能 import,那是不是也能访问全局对象”——不能。模块 Worker 的全局对象是 self,它没有 localStorage、document、window、fetch(除非显式启用,且部分浏览器仍限制)、console(有,但输出在 DevTools 的 Workers 面板下)。
典型陷阱:
- 在模块 Worker 里写
import { api } from './api.js',而api.js内部用了localStorage.getItem()→ 运行时报ReferenceError: localStorage is not defined - 想用
fetch加载模型权重?可以,但需确认目标域名允许跨域,且浏览器支持(Chrome ≥ 99、Firefox ≥ 91);否则改用主线程fetch后通过postMessage(..., [arrayBuffer])传输二进制
真正容易被忽略的是:模块 Worker 的错误堆栈默认不包含源映射,若用构建工具(如 Vite、Webpack)打包,务必开启 build.sourcemap 并确保 worker.js 的 sourcemap 被正确加载,否则调试时只能看到压缩后的一行代码。
本文共计861个文字,预计阅读时间需要4分钟。
普通Worker默认运行在classic模式,无法解析import语句;只有显式声明type: 'module',浏览器才会按ES模块规范加载并解析依赖。在不加选项时,不要害怕worker.js里只有一行import { foo } from './utils.js';,也会直接报错SyntaxError: Cannot use import statement outside a module。
模块 Worker 自动启用顶层 await、动态 import() 和裸 specifier 支持(需配合 importMap),但代价是:它完全禁用 importScripts() —— 所有依赖必须走标准 import 链。
new Worker() 路径必须是同源可访问的 URL
模块 Worker 对路径更敏感,常见失败原因:
-
new Worker('data:text/javascript,import%20x%20from%20"./a.js"')→ 不合法:DataURL 不支持模块解析,会报Failed to construct 'Worker': Module scripts are not supported for data URLs -
new Worker('./worker.js', { type: 'module' })→ 成功,但要求worker.js能被服务器以Content-Type: application/javascript+module或至少application/javascript返回 - 开发时用
file://协议打开 HTML → 所有模块 Worker 加载失败(CORS + 协议限制),必须起本地服务(如npx serve或 Vite)
主线程与模块 Worker 之间不能共享函数或类实例
即使双方都用 ES 模块,postMessage() 仍走结构化克隆算法,以下内容会被忽略或报错:
立即学习“前端免费学习笔记(深入)”;
-
postMessage({ fn: () => {} })→ 函数丢失,收端得到{} -
postMessage(new Date())→ 变成字符串,不是Date实例 -
postMessage(arrayBuffer, [arrayBuffer])→ 可转移,但接收方必须用e.data.buffer重新构造视图,不能直接当原 ArrayBuffer 用
正确做法是只传纯数据(Object、Array、Number、String、ArrayBuffer 等可克隆类型),复杂逻辑封装成序列化/反序列化协议,比如用 JSON.stringify() + JSON.parse() 控制字段粒度。
模块 Worker 中不能用 localStorage、document、window
这是所有 Worker 的共性,但模块 Worker 容易让人误以为“既然能 import,那是不是也能访问全局对象”——不能。模块 Worker 的全局对象是 self,它没有 localStorage、document、window、fetch(除非显式启用,且部分浏览器仍限制)、console(有,但输出在 DevTools 的 Workers 面板下)。
典型陷阱:
- 在模块 Worker 里写
import { api } from './api.js',而api.js内部用了localStorage.getItem()→ 运行时报ReferenceError: localStorage is not defined - 想用
fetch加载模型权重?可以,但需确认目标域名允许跨域,且浏览器支持(Chrome ≥ 99、Firefox ≥ 91);否则改用主线程fetch后通过postMessage(..., [arrayBuffer])传输二进制
真正容易被忽略的是:模块 Worker 的错误堆栈默认不包含源映射,若用构建工具(如 Vite、Webpack)打包,务必开启 build.sourcemap 并确保 worker.js 的 sourcemap 被正确加载,否则调试时只能看到压缩后的一行代码。

