JavaScript语法特性篇-动态导入 import()

1、基本使用

import() 语法,通常被称为动态导入,是一个类似函数的表达式,它允许异步和动态地将 ECMAScript 模块加载到一个可能不是模块的环境中。

与声明式的导入相对应,动态导入只在需要时进行计算,并且允许更大的语法灵活性。

简单来说,使用 import() 语法,你可以在运行时(而不是在编译时)决定要导入哪个模块,并且这种导入是异步的,不会阻塞代码的执行。

await import('/modules/my-module.js')

2、与静态导入区别

静态导入是在 JavaScript 模块中声明时直接指定要导入的模块,是 ES6 中标准导入的方式。

// mathFunctions.js  
export function add(a, b) {  
  return a + b;  
}  
  
export function subtract(a, b) {  
  return a - b;  
}

// main.js
// 静态导入 mathFunctions.js 中函数
import { add, subtract } from './mathFunctions.js';  
  
console.log(add(1, 2)); // 输出 3  
console.log(subtract(3, 1)); // 输出 2

动态导入使用 import() ,其调用非常类似于函数调用语法,但 import 本身是一个关键字,不是一个函数。它返回一个 Promise,这个 Promise 解析为导入的模块对象。

假设需要再用户点击按钮后才加载并执行某个模块中的代码,可以采用点击时触发动态导入。

// button.js  
document.querySelector('#loadModuleButton').addEventListener('click', async () => {  
  try {  
    const module = await import('./dynamicModule.js');
    // dynamicModule.js 导出了一个名为 dynamicFunction 的函数  
    console.log(module.dynamicFunction());
  } catch (error) {  
    console.error('Error loading module:', error);  
  }  
});

// dynamicModule.js  
export function dynamicFunction() {  
  return 'This is a dynamically loaded function!';  
}

当用户点击 ID 为 loadModuleButton 的按钮时,JavaScript 会异步加载并执行 dynamicModule.js 文件中的代码。

3、动态导入使用场景

导入声明语法(如 import something from "somewhere")是静态的,并且总是在加载时评估导入的模块。动态导入允许人们绕过导入声明的语法刚性,并条件性地或按需加载模块。以下是可能需要使用动态导入的一些原因:

  1. 当静态导入显著减慢代码加载速度或增加程序内存使用,并且你导入的代码被使用的可能性很低,或者直到稍后才需要它

  2. 当你要导入的模块在加载时不存在

  3. 当导入标识符字符串需要动态构造时。(静态导入仅支持静态标识符)

  4. 当被导入的模块有副作用,而你不想在条件不满足时产生这些副作用

  5. 当你处在一个非模块环境(例如,eval 或一个脚本文件)时

仅在必要时使用动态导入。对于加载初始依赖项,静态形式更可取,并且可以更容易地从静态分析工具和“树摇”中受益。

如果你的文件不是作为模块运行的(如果它在 HTML 文件中被引用,则 <script> 标签必须具有 type="module"),你将无法使用静态导入声明,但异步动态导入语法始终可用,允许你将模块导入到非模块环境中。

并非所有执行上下文都允许动态模块导入。例如,import ()可以在主线程、共享工作线程或专用工作线程中使用,但是如果在服务工作线程或工作线程中调用,则会抛出。

4、模块命名空间对象

模块命名空间对象是一个描述模块所有导出的对象。它是在模块评估时创建的静态对象。

有两种方法可以访问模块的模块命名空间对象:

  • 通过命名空间导入(import * as name from moduleName

  • 通过动态导入的 Promise fullfilled 值。

模块命名空间对象是一个封闭的、没有原型的对象。这意味着该对象的所有字符串键都对应于模块的导出,并且永远不会有多余的键。所有键都按照字典顺序可枚举(即 Array.prototype.sort() 的默认行为),默认导出可用作名为 default 的键。此外,模块命名空间对象有一个 @@toStringTag 属性,其值为 “Module”,可通过 Object.prototype.toString() 方法获取。

当你使用 Object.getOwnPropertyDescriptors() 获取属性的描述符时,字符串属性是不可配置的和可写的。但是,它们实际上是只读的,因为你不能将一个属性重新赋值为一个新值。这种行为反映了静态导入创建“实时绑定”的事实——这些值可以由导出它们的模块重新赋值,但不能由导入它们的模块重新赋值。属性的可写性反映了值可能会改变的可能性,因为不可配置和不可写的属性必须是常量。例如,你可以重新分配一个变量的导出值,并在模块命名空间对象中观察到新值。

每个模块标识符都对应一个唯一的模块命名空间对象,因此以下两个导入方式得到的模块命名空间对象是一致的:

import * as mod from "/my-module.js";

import("/my-module.js").then((mod2) => {
  console.log(mod === mod2); // true
});
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端后花园

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值