ES6:条件和动态导入语句


85

有条件的

是否可以像下面这样有条​​件的导入语句?

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中的大量导入?


1
在这种情况下不能使用继承吗?用于super致电特定。
2016年

我已经在使用继承,但是这些“页面”中包含“页面”特定的逻辑。我确实有一个基本的“页面”类,所有这些类都可以扩展,但这不足以清理大量的导入内容。
Enijar

1
@zerkms:它们不是从块中吊起的-它们是语法错误。
Bergi


Answers:


54

现在,ECMA确实有动态进口建议。这是在阶段2中。这也可以作为babel-preset使用

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

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

这基本上返回了一个承诺。承诺解决方案有望包含该模块。该提案还具有多个动态导入,默认导入,js文件导入等功能。您可以在此处找到有关动态导入的更多信息。


3
这个。动态导入是必经之路。它们像require()一样工作,除了它们给您一个承诺而不是一个模块。
superluminary

24

您不能像imports静态分析那样动态地解决依赖关系。但是,您可能会require在这里使用某些内容,例如:

for (let foo in bar) {
    if (bar.hasOwnProperty(foo)) {
        const Baz = require(foo).Baz;
    }
}

8
“因为进口是为了进行静态分析。” ---这句话含糊不清。imports被设计为导入,而不用于分析。
zerkms's

12
@zerkms-我认为它们的意思是import语句适合于静态分析-因为它们从来都不是有条件的,所以工具可以更轻松地分析依赖关系树。
Joe Clay

4
用“ foo”,“ baz”和“ bar”很难理解-一个真实的例子如何?
2016年

1
这不再是事实。现在,动态导入已成问题。参见此处:stackoverflow.com/a/46543949/687677
superluminary '18年

7

由于这个问题在Google中排名很高,因此值得一提的是,自从发布了较早的答案以来,情况已经发生了变化。

MDN在动态导入下具有以下条目:

可以将import关键字称为动态导入模块的函数。当以这种方式使用时,它返回一个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上找到有关该主题的有用文章。


1

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

  1. 询问您需要的模块
  2. 等待承诺返回模块

在ECMA Script中,支持使用SystemJS的延迟加载模块。当然,并非所有浏览器都支持此功能,因此与此同时,您可以使用JSPM或SystemJS垫片。

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


1

自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 Promise,所以async/await语法糖也是可能的:

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

现在考虑一下对象解构分配的可能性!例如,我们能够轻松地将命名出口中的一个出口存储在内存中以供后用:

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

或者,可以选择其中一个名为exports的名称,然后将其重命名为我们想要的其他任何名称:

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

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

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

只是最后(但并非最不重要)的注意事项: import()看起来像函数调用,但不是Function。这是一种特殊的语法,只是碰巧使用了括号(类似于发生的情况super())。因此,不可能分配import给变量或使用Function原型中的东西,例如call/ apply

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.