Node.js ES6环境下如何单行导入并运行模块
问题原因
报错核心是对ES动态import()的返回值存在认知偏差:
- CommonJS的
require()是同步API,执行后直接返回加载完成的模块导出值,因此可以直接在后方加括号完成调用 - ES规范中的动态
import()是异步API,调用后固定返回一个Promise对象,直接在import()后方追加('foo'),本质是尝试将返回的Promise实例作为函数调用,自然会抛出「不是函数」的错误。
另外需要注意:顶层静态import属于语法层面的静态声明,必须写在模块最外层作用域,不能嵌入Promise.all这类运行时代码块中,因此本身就不支持单行内嵌调用的写法。
可行方案
如果确实需要在Promise.all内单行完成导入+调用(适配按需加载、动态路径等场景),只需在动态import()的then回调中拿到真实模块导出后再执行调用即可,该写法为原生ES标准支持,无需TypeScript或额外编译工具:
Promise.all([ import('../path/to/a').then(mod => mod.default('foo')), import('../path/to/b').then(mod => mod.default('bar')), ]) .then(() => { // 后续业务代码 }) .catch(e => { console.log(e.message) })
写法说明
- 动态import加载完成后,resolve出的
mod是模块命名空间对象,此前通过import a from '../path/to/a'拿到的默认导出,实际就存储在该对象的default属性上,取mod.default即为需要调用的目标函数 - 如果模块使用命名导出(例如
export const a = () => {}),对应取对应导出属性调用即可,例如mod.a('foo')
补充建议
如果a、b两个模块是当前模块初始化必须依赖的资源,更推荐使用顶层静态import写法:
import a from '../path/to/a' import b from '../path/to/b' Promise.all([ a('foo'), b('bar'), ]) .then(() => { // further code }) .catch(e => { console.log(e.message) })
静态import会在代码执行前完成模块解析加载,支持静态分析,打包工具可对其做tree-shaking优化,加载性能和稳定性都优于动态import,仅在按需加载、动态路径等特殊场景下才需要使用动态import写法。
内容的提问来源于stack exchange,提问作者GʀᴜᴍᴘʏCᴀᴛ
相关产品推荐
相关产品推荐

