【发布时间】:2025-10-14 11:35:02
【问题描述】:
我有一个需要在启动时动态加载多个脚本的网络应用程序。为了提高效率,它需要通过网络并行请求所有脚本。为了正确起见,脚本必须按特定顺序执行。
在 DOM 中,这可以通过动态添加 <script> 标签并将 async 属性设置为 false 来实现。请求并行发出,脚本按照添加标签的顺序运行。
在经典类型的Web Worker(默认)中,可以使用importScripts(...arr)。浏览器一次性获取所有脚本的列表,因此可以同时请求它们,但要保证脚本按指定的顺序运行。
在模块类型的 Web Worker 中,事情变得更加棘手。 importScripts 不允许在模块类型工作者中使用(如果您尝试,Chrome 会抛出 Module 脚本不支持 importScripts())。工人不能添加脚本标签。但是,您可以使用动态 import() - 但它只接受一个脚本。如果您像这样一次导入一个脚本:
async LoadScripts(scriptsArr)
{
for (const src of scriptsArr)
await import(src);
}
这样会序列化网络请求一个接一个地运行,效率低。
我唯一能想到的就是动态创建一个仅包含 import '...'; 行的模块,然后动态导入它,如下所示:
async LoadScripts(scriptsArr)
{
// Create a string with a module full of import statements
const moduleStr = scriptsArr.map(src => `import '${src}';`).join("\n");
// Create a blob from the string
const blob = new Blob([moduleStr], { type: "application/javascript" });
// Dynamic import the blob, which in turn loads all the import statements
await import(URL.createObjectURL(blob));
}
这感觉就像一个非常丑陋的黑客,就像一个美化的eval()。有没有更好的办法?
【问题讨论】:
-
"我有一个 web 应用程序需要在启动时动态加载多个脚本" - 你能详细说明一下要求吗?为什么它是动态的,它如何决定哪些脚本需要加载,哪些不需要?如果它们以意外的顺序加载会出现什么问题?
-
我们在浏览器中制作了 Construct 3,一个完整的游戏开发 IDE。游戏预览在本地工作并且是模块化的,可能包括本地安装的第三方插件。所以在预览中加载的脚本没有固定的列表,依赖运行时的第三方脚本必须在运行时脚本之后,并且运行时也有自己的内部依赖项(正如我在另一条评论中提到的,我们正在从经典脚本迁移,所以还没有导入依赖链)
-
我认为对于没有服务器交互的预览功能,
createObjectURL是一个非常好的和合适的解决方案。然后,游戏的实际构建可能会将其生成为静态文件。
标签: javascript performance web-worker es6-modules dynamic-import