我有一个网络应用程序需要在启动时动态加载多个脚本。为了提高效率,它需要通过网络并行请求所有脚本。为了正确起见,脚本必须按特定顺序执行。
在 DOM 中,这可以通过动态添加 <script>
来实现带有 async
的标签属性设置为 false
.请求并行发出,脚本按照添加标签的顺序运行。
在经典类型的 Web Worker(默认)中,您可以使用 importScripts(...arr)
.浏览器一次性获得所有脚本的列表,因此可以同时请求所有脚本,但要保证脚本按指定的顺序运行。
在模块类型的 Web Worker 中,事情变得更加棘手。 importScripts
在模块类型 worker 中是不允许的(如果您尝试,Chrome 将抛出 Module scripts don't support importScripts())。 worker 不能添加脚本标签。但是,您可以使用动态 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));
}
虽然这感觉像是一个非常丑陋的 hack,就像一个美化的 eval()
.有没有更好的办法?
最佳答案
For correctness the scripts must execute in a specific order.
如果脚本确实有依赖关系,则应使用 import 语句显式声明这些依赖关系。
创建一个以正确顺序导入所有内容的单个模块,就像您正在动态构建的模块一样,也是一种选择,可能模块列表实际上是相当静态的。
If you import scripts one at a time, it serializes the network requests to run one after another, which is inefficient.
如果模块声明了它们的依赖关系,您可以一次加载它们:
function loadScripts(scriptsArr) {
return Promise.all(scriptsArr.map(src => import(src));
}
关于javascript - 模块类型 Web Worker 中多个脚本的高效动态导入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63018101/