ES6:条件和动态导入语句

IT技术 javascript ecmascript-6
2021-01-24 19:56:21

有条件的

是否可以有如下条件导入语句?

if (foo === bar) {
    import Baz from './Baz';
}

我已经尝试了上述方法,但在编译时出现以下错误(来自 Babel)。

'import' and 'export' may only appear at the top level

动态的

是否可以有如下动态导入语句?

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        import Baz from `./${foo}`;
    }
}

上面在编译时从 Babel 收到相同的错误。

这是可能的还是我遗漏了什么?

推理

我尝试这样做的原因是我有很多“页面”的导入,并且它们遵循类似的模式。我想通过使用动态 for 循环导入这些文件来清理我的代码库。

如果这是不可能的,那么有没有更好的方法来处理 ES6 中的大量导入?

5个回答

我们现在有 ECMA 的动态导入提案。这是在第 2 阶段。这也可以作为babel-preset 使用

以下是根据您的情况进行条件渲染的方法。

if (foo === bar) {
    import('./Baz')
    .then((Baz) => {
       console.log(Baz.Baz);
    });
}

这基本上返回了一个Promise。Promise的决议有望有module。该提案还包含多个动态导入、默认导入、js 文件导入等内容。您可以在此处找到有关动态导入的更多信息

这。动态导入是要走的路。它们就像 require() 一样工作,除了它们给你一个Promise而不是一个module。
2021-03-15 19:56:21

您无法动态解析您的依赖项,这imports意味着静态分析。但是,您可能可以require在这里使用一些,例如:

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}
这不再是事实。动态导入现在是一回事。请参阅此处:stackoverflow.com/a/46543949/687677
2021-03-14 19:56:21
“因为进口是用于静态分析的。”---这个说法是含糊的。imports 旨在导入,而不是用于分析。
2021-03-31 19:56:21
@zerkms - 我认为他们的意思是import语句适合静态分析 - 因为它们从来没有条件,工具可以更容易地分析依赖树。
2021-04-04 19:56:21
很难理解“foo”、“baz”和“bar”——一个真实的例子怎么样?
2021-04-07 19:56:21

由于谷歌对这个问题的排名很高,值得指出的是,自从旧的答案发布以来,情况已经发生了变化。

MDN 在Dynamic Imports下有这个条目

import 关键字可以作为函数调用来动态导入module。以这种方式使用时,它会返回一个Promise。

import('/modules/my-module.js')
  .then((module) => {
    // Do something with the module.
  });

// This form also supports the await keyword.
let module = await import('/modules/my-module.js');

可以在Medium上找到有关该主题的有用文章

自 2016 年以来,JavaScript 世界已经过去了很多,所以我相信是时候提供关于这个主题的最新信息了。目前动态进口是一个现实在节点浏览器上(本地,如果你不关心IE浏览器,或@巴贝尔/插件语法动态导入,如果你做护理)。

因此,考虑一个something.js具有两个命名导出和一个默认导出的示例模​​块

export const hi = (name) => console.log(`Hi, ${name}!`)
export const bye = (name) => console.log(`Bye, ${name}!`)
export default () => console.log('Hello World!')

我们可以使用import()语法轻松干净地有条件地加载它:

if (somethingIsTrue) {
  import('./something.js').then((module) => {
    // Use the module the way you want, as:
    module.hi('Erick') // Named export
    module.bye('Erick') // Named export
    module.default() // Default export
  })
}

但由于返回的是 a Promiseasync/await语法糖也是可能的:

async imAsyncFunction () {
  if (somethingIsTrue) {
    const module = await import('./something.js')
    module.hi('Erick')
  }
}

现在想想对象解构赋值的可能性例如,我们可以轻松地将这些命名导出中的一个放入内存中以供后用:

const { bye } = await import('./something.js')
bye('Erick')

或者也许可以获取这些命名导出之一并将其重命名为我们想要的任何其他内容:

const { hi: hello } = await import('./something.js')
hello('Erick')

或者甚至将默认导出的函数重命名为更有意义的名称:

const { default: helloWorld } = await import('./something.js')
helloWorld()

最后(但并非最不重要)注意: import()可能看起来像一个函数调用,但它不是Function. 这是一种恰好使用括号的特殊语法(类似于 发生的情况super())。所以不可能分配import给变量或使用Function原型的东西,比如call/ apply

Require 不会解决您的问题,因为它是一个同步调用。有几种选择,它们都涉及

  1. 索取您需要的module
  2. 等待Promise返回module

在 ECMA 脚本中,支持使用 SystemJS 的延迟加载module。当然,并非所有浏览器都支持此功能,因此同时您可以使用 JSPM 或 SystemJS shim。

https://github.com/ModuleLoader/es6-module-loader