当前位置: 首页 > news >正文

ES Module 的 import 导入和 import () 动态导入

ES Module 的 import 导入和 import () 动态导入介绍

一、ES Module 简介

ES Module 是 JavaScript 官方提供的标准化模块系统,它的出现解决了长期以来 JavaScript 在模块管理方面的混乱局面。通过 ES Module,开发者可以更加方便地组织和复用代码,提高代码的可维护性和可扩展性。

二、import 导入

(一)基本语法

import 默认导出

在一个模块中,可以使用export default来定义默认导出。例如,在myModule.js文件中:

// myModule.js

const myFunction = () => {
  console.log("这是一个默认导出的函数");
};

export default myFunction;

在另一个模块中导入这个默认导出:

// main.js

import myFunction from "./myModule.js";

myFunction(); // 输出:这是一个默认导出的函数

import 具名导出

模块中也可以使用具名导出,将多个变量、函数或类分别导出。例如:

// mathModule.js

export const add = (a, b) => a + b;

export const subtract = (a, b) => a - b;

在其他模块中导入具名导出:

// main.js

import { add, subtract } from "./mathModule.js";

console.log(add(2, 3)); // 输出:5

console.log(subtract(5, 3)); // 输出:2

也可以给 import 的具名导出起别名:

// main.js

import { add as sum, subtract as difference } from "./mathModule.js";

console.log(sum(2, 3)); // 输出:5

console.log(difference(5, 3)); // 输出:2

混合导入

一个模块可以同时有默认导出和具名导出,在导入时也可以混合使用:

// myModule.js

const myDefaultFunction = () => {
  console.log("这是默认导出的函数");
};

export const myVariable = 42;

export default myDefaultFunction;
// main.js

import myDefaultFunction, { myVariable } from "./myModule.js";

myDefaultFunction(); // 输出:这是默认导出的函数

console.log(myVariable); // 输出:42

(二)import 的特点

静态性import语句在编译阶段就会被解析,这意味着它不能出现在运行时才执行的逻辑中,比如if语句块内。这使得 JavaScript 引擎可以在代码执行前对模块依赖进行分析和优化。

提升import语句会被提升到模块的顶部,即使在代码中它出现在其他语句之后,也会先于其他语句执行。

三、import () 动态导入

(一)基本语法

import()是 ES2020 引入的动态导入语法,它返回一个Promise。这使得我们可以在运行时根据条件动态地加载模块。例如:

// main.js

const condition = true;

if (condition) {
  import("./myModule.js")
    .then((module) => {
      module.default(); // 假设 myModule.js 有默认导出
    })
    .catch((error) => {
      console.error("加载模块失败", error);
    });
}

如果模块是具名导出,可以这样使用:

// main.js

import("./mathModule.js")
  .then((module) => {
    console.log(module.add(2, 3)); // 假设 mathModule.js 有具名导出 add 函数
  })
  .catch((error) => {
    console.error("加载模块失败", error);
  });

(二)支持导入 CommonJS

在 Node.js 环境中,import()语法还支持导入 CommonJS 模块。CommonJS 是一种广泛使用的 JavaScript 模块规范,尤其是在 Node.js 应用中。当使用import()导入 CommonJS 模块时,需要注意以下几点:

转换规则

CommonJS特性ESM转换表现
module.exports成为默认导出default属性
exports.xxx转换为具名导出属性
exports.default不会特殊处理
动态导出可能无法正确识别
const cjsModule = await import('./legacy-module.cjs');
console.log(cjsModule.default); // 默认导出
console.log(cjsModule.namedExport); // 具名导出

默认导出与命名导出:CommonJS 模块只有一个exports对象用于导出内容,通过import()导入时,默认导出的是整个exports对象。例如,有一个 CommonJS 模块commonModule.js

// commonModule.js(CommonJS模块)

const myValue = 10;

exports.myValue = myValue;

exports.anotherFunction = () => {
  console.log("这是CommonJS模块中的另一个函数");
};

在 ES Module 中使用import()导入该模块:

// main.js

import("./commonModule.js")
  .then((module) => {
    console.log(module.myValue); // 输出:10

    module.anotherFunction(); // 输出:这是CommonJS模块中的另一个函数
  })
  .catch((error) => {
    console.error("加载模块失败", error);
  });

兼容性:虽然import()支持导入 CommonJS 模块,但在不同的运行环境中,其兼容性可能有所不同。在 Node.js 中,从 Node.js 13.2.0 版本开始原生支持通过import()导入 CommonJS 模块。在浏览器环境中,情况相对复杂,一些现代浏览器可能对导入 CommonJS 模块的支持并不完善,这时候可能需要借助工具如 Babel 和 Webpack 来进行处理,将 CommonJS 模块转换为 ES Module 格式,以确保代码在各种环境中都能正常运行。

(三)import () 的优势

代码拆分:在大型应用中,通过import()可以实现代码的按需加载,将应用的代码拆分成多个小块,只有在需要的时候才加载相应的模块,从而提高应用的初始加载性能。

条件加载:可以根据运行时的条件来决定加载哪个模块,增加了代码的灵活性。例如,根据用户的语言偏好加载不同语言的翻译模块。

(四)import() 导入如何清除缓存

在使用import()动态导入模块时,缓存机制可能会导致加载旧版本的模块内容。根据模块类型不同,清除缓存的方式也有所差异。

导入 ES Module :ES Module 的缓存机制相对严格,要确保每次都加载最新文件,可在每次调用import()时,对文件地址添加不同的查询参数,以此强制浏览器或 Node.js 重新请求该模块。例如:

const modulePath = './myModule.js';
const uniqueModulePath = `${modulePath}?v=${Date.now()}`;
import(uniqueModulePath)
  .then((module) => {
        // 使用模块
    })
  .catch((error) => {
        console.error('加载模块失败', error);
    });

上述代码通过Date.now()生成一个随时间变化的唯一值作为查询参数,确保每次请求的模块路径不同,从而避免缓存。

导入 Common JS 模块:在 Node.js 环境中,CommonJS 模块的缓存管理与 ES Module 不同。若要手动清除缓存,需借助require方法。在 ES Module 中,本身没有直接的require方法,但可通过以下方式获取:

import { createRequire } from "module";
const require = createRequire(import.meta.url);

获取require方法后,就能像在 Common JS 模块中一样清除缓存。假设要动态加载并确保每次获取最新的 Common JS 模块legacyModule.cjs:

const modulePath = './legacyModule.cjs';
delete require.cache[require.resolve(modulePath)];

const module = require(modulePath);
//  也可以使用import()
import(modulePath).then((module)=>{
	console.log(module)
})

这段代码先通过require.resolve(modulePath)获取模块在缓存中的路径,再从require.cache中删除该路径对应的缓存,确保下次require / import 时重新加载模块。

通用加载方案:若不确定要加载的模块是 ES Module 还是 Common JS 模块,可构建一个通用的加载函数,综合上述两种方式来处理缓存问题。以下是一个示例:

import path from "path";
import { pathToFileURL } from "url";
import { createRequire } from "module";
const require = createRequire(import.meta.url);

function loadFile(filePath) {
  delete require.cache[require.resolve(filePath)];
  const fileUrl = pathToFileURL(path.resolve(filePath)).href;

  const urlWithCacheBuster = `${fileUrl}?v=${Date.now()}`;
  return import(urlWithCacheBuster)
    .then((module) => {
      return module.default || module;
    })
    .catch((err) => {
      console.error(`文件加载失败 ${modulePath}:`, err);
    });
}

export { loadFile };

此函数loadFile 首先手动清除 Common JS 模块的缓存,再通过添加查询参数避免ES Module缓存;最后通过import 加载文件。这样无论模块是何种类型,都能尽可能确保加载到最新内容。

四、import 和 import () 的区别

静态与动态import是静态导入,在编译阶段确定依赖关系;import()是动态导入,在运行时确定依赖关系。

使用场景import适用于那些在模块初始化时就需要加载的依赖;import()更适合用于代码拆分和条件加载的场景。

语法形式import是声明式语法,而import()是函数调用语法,返回一个Promise

五、总结

ES Module 的import导入和import()动态导入为开发者提供了强大的模块管理能力。import的静态特性使得代码的依赖关系更加清晰,便于优化;import()的动态特性则为代码的灵活性和性能优化提供了更多可能。在实际开发中,我们应根据具体的需求选择合适的导入方式,以构建高效、可维护的 JavaScript 应用。

相关文章:

  • Blueprint —— Blueprint Editor(二)
  • 牛客周赛A:84:JAVA
  • 【移动WEB开发】rem适配布局
  • 【Kotlin】Kotlin基础笔记
  • 用python 的 sentiment intensity analyzer的情感分析器,将用户评论进行分类
  • HPC超算系列4——官方指南文档
  • Dify使用日常:我是如何按标题级别将word中的内容转存到excel中的
  • ESP32驱动OV3660摄像头实现EdgeImpulse图像识别(摄像头支持红外夜视、边缘AI计算)
  • 【AI】什么是Embedding向量模型?我们应该如何选择?
  • 论文不能抄要怎么写啊?
  • 网络空间安全(21)验证码安全
  • 【springcloud】快速搭建一套分布式服务springcloudalibaba(二)
  • 【机器学习和深度学习】分类问题通用评价指标:精确率、召回率、准确率和混淆矩阵
  • es-初体验easy-es时报错:找不到mapper
  • 使用 Docker 部署 Nginx,配置后端 API 轮询与多个子域名前端应用
  • Java中局部变量、实例变量和静态变量的运行时数据区域
  • 云效、流水线、Gradle缓存问题、build.gradle配置snapshot
  • 每天五分钟深度学习框架PyTorch:使用残差块快速搭建ResNet网络
  • JDBC 的连接
  • 分布式ID
  • 网站后台管理员做链接/bt磁力链好用的引擎
  • 网站导航条/站长工具四叶草
  • 做哪个视频网站赚钱/建站软件
  • 信阳做房产哪个网站好用/中国工商业联合会
  • 自己做网站买/如何提高网站搜索排名
  • 政府网站群建设中标公告/重庆森林经典台词图片