【问题标题】:ES6: Conditional & Dynamic Import StatementsES6:条件和动态导入语句
【发布时间】:2016-06-25 04:37:19
【问题描述】:

有条件的

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

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 中是否有更好的方法来处理大量导入?

【问题讨论】:

  • 这种情况下不能使用继承吗?使用super 调用具体。
  • 我已经在使用继承,但是这些“页面”中包含“页面”特定的逻辑。我确实有一个可以扩展的基本“页面”类,但这不足以清理我拥有的大量导入。
  • @zerkms:它们不是从块中取出的——它们是语法错误。
  • ES6 variable import name in node.js 的可能重复项?

标签: javascript ecmascript-6


【解决方案1】:

我们现在确实有 ECMA 的动态导入提案。这是在第 2 阶段。也可以通过 babel-preset 获得。

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

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

这基本上返回了一个承诺。承诺的解决方案有望具有该模块。该提案还包含多个动态导入、默认导入、js 文件导入等内容。您可以找到有关dynamic imports here 的更多信息。

【讨论】:

  • 这个。动态导入是要走的路。它们就像 require() 一样工作,除了它们给你一个承诺而不是一个模块。
【解决方案2】:

您无法动态解析您的依赖关系,因为imports 用于静态分析。但是,您可能可以在这里使用一些require,例如:

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

【讨论】:

  • “因为导入是为了静态分析。” --- 这句话是含糊的。 imports 旨在导入,而不是用于分析。
  • @zerkms - 我认为它们的意思是 import 语句应该适合用于静态分析 - 因为它们从来不是有条件的,工具可以分析依赖关系树更容易。
  • 用“foo”、“baz”和“bar”很难理解——现实生活中的例子怎么样?
  • 这不再是真的。动态导入现在是一回事。见这里:stackoverflow.com/a/46543949/687677
【解决方案3】:

由于该问题在 Google 中的排名很高,因此值得指出的是,自从发布较早的答案以来,情况发生了变化。

MDN 在Dynamic Imports 下有这个条目:

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找到。

【讨论】:

    【解决方案4】:

    自 2016 年以来,JavaScript 世界已经发生了很多事情,所以我相信是时候提供有关此主题的最新信息了。目前Dynamic imports 已成为现实on Nodeon browsers(如果您不关心 IE,则为原生,如果您关心,则使用 @babel/plugin-syntax-dynamic-import)。

    因此,考虑一个示例模块 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
      })
    }
    

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

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

    现在想想Object Destructuring Assignment 的可能性!例如,我们可以轻松地将其中一个命名的导出放入内存中以供以后使用:

    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

    【讨论】:

      【解决方案5】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-05-28
        • 1970-01-01
        • 1970-01-01
        • 2013-04-15
        • 1970-01-01
        • 2018-06-03
        • 2015-08-01
        • 2021-05-17
        相关资源
        最近更新 更多