import 与 require 详解 - 从深入浅处Node带来的思考

本文探讨了Node.js中的require与ES6的import的关系和异步加载方式。require是Node中实现的CommonJS规范,而import是ES2015的模块加载规范,通常通过webpack转换为require。在浏览器端,import支持异步加载,如import(),而在Node.js中,require不直接支持异步加载。文章还分析了require.ensure和import()的用法,以及服务器与客户端统一模块加载的可能性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在开头

今天在阅读深入浅处node.js的时候读到了这段描述:


2.7 前后端共用模块

谈论了许多后端模块的具体实现之后,现在我们围绕CommonJS规范再次回到前端模块上。JavaScript在Node出现之后,比别的编程语言多了一项优势,那就是一些模块可以在前后端实现共用,这是因为很多API在各个宿主环境下都提供。但是在实际情况下,前后端的环境是略有差别的。

2.7.1模块的侧重点

前后端JavaScript分别搁置在HTTP的两端,他们扮演的角色并不同。浏览器的JavaScript需要经历从同一个服务器分发到多个客户端执行,而服务器端JavaScript则是相同的代码需要多次执行。前者的瓶颈在于带宽,后者的瓶颈在于CPU和内存等资源。前者需要通过网络加载代码,后者从磁盘中加载,两者的加载速度不在一个数量级上。

纵观Node的模块引入过程。几乎全都是同步的。尽管与Node强调异步的行为有些相反,但它是合理的。但是如果前端模块也采用同步的方式来引入,那将会在用户体验上造成很大的问题。UI在初始化过程中需要花费很多时间来等待脚本加载完成


接下来,作者分析了CommonJS还列举了AMD,CMD的异步加载模式,但是由于书的出版时间是2013年了,作者并未介绍时下流行的ES6 Import语法。
那么我就产生了如下的问题

  1. require与import之间有何关系呢?
  2. require是否支持异步加载资源来满足浏览器端开发的需求呢?
  3. 服务器端与浏览器端是否可以使用统一的模块加载机制呢?

由于本人水平有限,很多内容参考网络上其他大牛的文章。如似曾相识,希望轻喷。

require与import的关系

require是在Node中根据CommonJS规范实现的模块加载函数,而import则是ES2015所提出的模块加载规范。现如今require已在Node环境中进行了实现,而import则在chrome等最新版的现代浏览器中部署了。从上描述可看出require是遵循CommonJS规范的模块加载语法,而import则是在ES2015中提出的新的模块加载规范,两者之间似乎毫无联系,但import也只是近期在的浏览器端是实现了,而我们在写项目代码时却可以毫不顾及的使用import语法进行模块导入,这究竟是如何做到的呢?

这是因为import被webpack转换成了require语法,因此我们才可以在项目中毫无阻碍的使用import。这让我想到了一个问题-网络上有许多文章在分析require与import之间的差异,其中还有提到import是异步加载而require是同步加载的理论,这就让我产生了极大的疑问:既然import语法是通过转换成require语法实现的那么他们所谓的差异结论是如何得出的呢?是因为webpack或者其他import模块的实现机制导致的还是官方规范所制定的规范明确定义的呢? 于是乎带着疑问我就开始查找require与import的官方规范。

CommonJS官方规范,通过阅读CommonJS规范,发现CommonJS规范包含词法,类型,上下文,表达式,声明,方法,对象等语言的基本要素,而并没有对是否异步或者同步等进行规定。接着我又带着疑问查找了import官方规范然后又阅读了文章2ality – JavaScript and more,发现import的规范也只是定义了import的词法,类型,表达式,基础语法等,并且在JavaScript and more的文章中更是明确指出import是静态的文件导入但也支持异步的方法。并且我在StackOverflow技术论坛上也看到了大牛关于import是异步还是同步的讨论-地址:Using Node.js require vs. ES6 import/export,并且附上我所关心内容的截图:

import模块实现机制

异步加载言论讨论

通过阅读上述资料,我得出以下观点:

  1. import规范由于不同模块的实现机制不同,所以存在差异。
  2. 在使用webpack打包工具后,import会被转换成require的CommonJS实现。
  3. chrome浏览器支持了import语法。(浏览器端import与webpack的import之间的差异以后有机会再做分析)

require与import的异步加载

对于客户端开发可能存在如需求: 当用户点击按钮之后再加载JS代码,这样做是为了进行懒加载,从而提高首页加载的性能。webpack就提供了require.ensure()方法来异步加载脚本,而import则由规范定义import()进行异步加载并且在webpack和chrome等现代浏览器都进行了实现,接着我们就详细介绍require.ensure()和import()

require.ensure

require.ensure方法是在webpack中定义实现的(注意node native环境中是没有require.ensure的),并且先已被import()给取代了,但是如果我们接收了老的项目,则有可能遇到require.ensure,因此接下来对其用法进行科普:

require.ensure的基础用法:

require.ensure(
  dependencies: String[],
  callback: function(require),
  errorCallback: function(error),
  chunkName: String
)

dependencies: 一个字符串数组,包含所有需要在回调中执行的模块。

callback: 当所有依赖都加载完成之后执行的回调函数,并且require函数将作为参数传递给回调函数,以使其能够进一步的require需要的模块。

errorCallback: 当webpack加载模块失败后执行的函数。

chunkName: require.ensure所创建的块的名称,当讲块名称传递给其他require.ensure函数时,可以将代码合并成一个块并最终打包成一个前端浏览器需要请求的包。

import()

动态的加载模块,对import()的调用会被当做分割点,意味着所请求的模块和它的子模块会被分割到独立的块中。并且import()会返回Promise用于处理回调。

if ( module.hot ) {
  import('lodash').then(_ => {
    // Do something with lodash (a.k.a '_')...
  });
}

异步请求场景

使用import()进行举例,因为require.ensure已被import()取代。

按需加载

一些web应用的功能不需要在启动时加载,那么就可以使用按需加载的手段。import()就可以提供帮助,例如:

button.addEventListener('click', event => {
    import('./dialogBox.js')
    .then(dialogBox => {
        dialogBox.open();
    })
    .catch(error => {
        /* Error handling */
    })
});
条件加载

有时需要根据某些条件来加载模块,例如:(记住使用polyfill来兼容遗留平台)

if (isLegacyPlatform()) {
    import(···)
    .then(···);
}
计算模块标识符

对于需要国际化的应用,就可以使用动态计算模块标识符的功能,例如:

import(`message_${getLocale()}.js`)
.then(···);

在查阅资料之后,发现require只是由webpack提供了require.ensure的异步加载模块方案,但是node native环境下貌似并不支持异步require,这也是由于node运行在服务器端的特性所导致的,因为进行的是磁盘读写,并不像客户端进行的网络请求,读写速度的差异导致node没有必要实现异步require来提升性能。

服务器与客户端统一的模块加载

在查找资料并且自己分析之后,发现现在的模块加载机制有node native的CommonJS, ES6的import,AMD,CMD,而其中import作为标准规范我认为迟早会在node端进行支持,并且在查找node官方API后其实node已经支持import语法,只不过还是实验性的传送门, 现代浏览器比如chrome.66之后也对import进行了支持。那么我们有理由相信在不久的将来import规范将作为服务器与客户端统一的模块加载语法。

写在最后

本片文章来来回回折腾了一周左右,由于工作还有自己知识的薄弱导致文章进度缓慢。不过好在最终完成了该文章,希望这篇文章能给大家带来帮助。

如有错误希望斧正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值