JS - 如何将多个动态导入批处理为一个?

JS - how to batch multiple dynamic imports into one?

我几乎同时从我的 JS 应用程序请求了两个独立但依赖的动态导入。如何避免进行两次导入调用或将它们批量合并为一个?

您可以结合 URL.createObjectURL() 和动态导入的强大功能,在一次 HTTP 调用中导入多个文件。

服务器设置

您显然需要某种 api 来在一次 API 调用中获取多个文件。为此,您需要让服务器以某种方式在一个 HTTP 响应中发送多个文件。语法可能会有所不同,但对于这个例子,我使用语法 GET /a.js+b.js,它将 return 一个字符串。

示例:16 24;export default 3export default [2, 3, 5]。这有两个文件,一个长度为 16 个字符,一个长度为 24; 之前的数字就像文件内容的元数据。不知道你可以把元数据放在 headers 之类的地方,但是这个例子使用 ; 来分隔元数据和内容。

客户端代码

我创建了一个名为 fetchMultiple 的函数,它类似于 fetch,但它 return 是 Promise<Array<Promise< the data exported by the files >>>

// I created a syntax where it goes
// {length of file 1} {length of file 2} {...lengths of files};(no \n)
// {contents of file 1} {contents of file 2} {...contents of files}
const mockServerResponses = new Map()
  .set('a.js+b.js', '16 24;export default 3export default [2, 3, 5]')

// The real thing would fetch the files from the server
const fetchMultiple = async (...urls) => 
  mockServerResponses.get(urls.join('+'))

// You could probably optimize this function to load the first script as soon as it is streamed, so that the first script will be loaded while the second one is still being streamed.
const importMultiple = async (...urls) => {
  const result = await fetchMultiple(...urls)
  const semi = result.indexOf(';')
  const lengths = result.slice(0, semi).split(' ').map(str => 
    parseInt(str))
  const rawContents = result.slice(semi + 1)
  let currentIndex = 0
  const contents = []
  for (const length of lengths) {
    contents.push(rawContents.slice(currentIndex, currentIndex + length))
    currentIndex += length
  }
  return contents.map(content => 
    import(URL.createObjectURL(new Blob(
      [content], 
      { type: 'application/javascript' }
    ))))
}

importMultiple('a.js', 'b.js')
  .then(promises => Promise.all(promises))
  .then(console.log)

如果代码段停止工作(如内容安全策略更改),这里是 link 回复:https://replit.com/@Programmerraj/dynamic-import-url#script.js

优化

可能使上面的示例变慢的原因是它等待整个两个(或更多)文件被提取,然后加载它们。由于文件是流式传输 file 1, file2, ...files,更快的代码会在可用时立即加载 file 1,并在下载其他文件时加载它们。

我没有实现这个优化流的东西,因为我没有设置一个服务器来流式传输响应,但你可以实现最大效率。