2020年9月15日(require和import)


在平常写vue或者react的项目时,我大多数时候写的是import,在写nodeJs的时候使用的都是require这种形式导入,因为nodeJs里面不支持ES Module

在有一次写项目(react+echarts)的过程中,要导入json数据,于是我还是使用的是import导入,结果同事要我换成require,因为require是同步,import是异步

基本概念

require用于读取并执行js文件, 并返回该模块的exports对象, 若无指定模块, 会报错。 Node使用CommonJS模块规范, CommonJS规范加载模块是同步的, 只有加载完成, 才能执行后续操作。

每一个文件就是一个模块,拥有自己独立的作用域,变量,以及方法等,对其他的模块都不可见。CommonJS规范规定:每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。require方法用于加载模块。

import用于引入外部模块, 其他脚本等的函数, 对象或者基本类型。 import属于ES6的命令, 它和require不一样, 它会生成外部模块的引用而不是加载模块, 等到真正使用到该模块的时候才会去加载模块中的值。

requir动态编译

第一次加载某个模块时, Node会缓存该模块, 后续加载就从缓存中获取。require是运行时调用,所以require理论上可以运用在代码的任何地方。但是使用CommonJS会使打包体积变大https://mp.weixin.qq.com/s/ITBFo8UE9LNxhhX-vvTCVw

import静态编译

ES6模块的编译: import模块时只是生成引用, 等到需要时才去取值, 所以不存在缓存的问题, 而且模块里的变量, 绑定其所在的模块。import是编译时调用,虽然import命令具有提升效果,会提升到整个模块的头部, 但还是建议放在文件开头。

在node中使用ES6模块

node要求ES6模块的后缀名为mjs,commonJS为cjs,如果不希望更改后缀名,可以设置package.json的type字段为module,require命令不能加载mjs,import命令也不能加载cjs,必须使用import

CommonJS加载ESModule

可以使用import(),require()不支持 ES6 模块的一个原因是,它是同步加载,而 ES6 模块内部可以使用顶层await命令,导致无法被同步加载。

ESModule加载CommonJS

ES6 模块的import命令可以加载 CommonJS 模块,但是只能整体加载,不能只加载单一的输出项。这是因为 ES6 模块需要支持静态代码分析,而 CommonJS 模块的输出接口是module.exports,是一个对象,无法被静态分析,所以只能整体加载。


Author: wxy
Reprint policy: All articles in this blog are used except for special statements CC BY 4.0 reprint policy. If reproduced, please indicate source wxy !
  TOC