为什么会有同步和异步模块的规范?

3
我刚刚读完了这篇有关JavaScript模块的文章。我理解CommonJS模块是同步加载的,而AMD模块是异步加载的。
但我不明白的是,如果我按照CommonJS格式编写模块,它如何变得“神奇地同步”?或者如果我按照AMD格式编写模块,它又如何变得“神奇地异步”?我的意思是,JavaScript甚至没有一个“define”或“require”关键字。它们只是规范,而不是库。
我的理解是,模块加载的行为取决于模块加载器,而不是模块的结构。如果是这样的话,为什么要为不同类型的模块遵循编码模式呢?
如果我的上述假设是正确的,那么为什么会有UMD规范呢?我的意思是,如果脚本基于其所在的环境进行加载,那么为什么要制定通用模块加载规范呢?
有人能帮我解决这个困惑吗?

模块的加载方式对代码没有影响 - 你对模块内部代码的假设是你的绊脚石。 - Jaromanda X
@JaromandaX 是的,那么为什么会有模块规格?您能否详细说明一下您的意思? - ng.newbie
模块本身并不变成同步或异步,它只是调用哪种类型的加载器接口。CJS格式假定同步加载器,在浏览器中效果不佳,因此创建了AMD格式以允许异步体执行(回调)的依赖声明。AMD也可以与同步加载器一起使用。 - Bergi
2个回答

6
这是一个很好的问题。这个主题在Node社区引起了很多激烈的讨论。要全面了解它,您应该阅读以下内容: 现在回答您的问题-为什么会有同步和异步模块的规范?因为有些用例更喜欢同步加载模块,比如在Node.js中的服务器端模块中,您希望在开始服务请求之前加载所需的所有内容;而有些用例更喜欢异步加载模块,比如在浏览器中,您不希望在加载依赖项时阻止渲染线程。
在浏览器中实际上没有同步加载的选项,因为它会使浏览器无响应。
您可以认为在服务器上使用异步加载,但是那样您将不得不通过require()返回承诺而不是模块,或者它可能需要回调。无论哪种方式,都将使使用许多模块的任何复杂代码更加复杂。
另一个问题是缓存和已加载模块的突变。通过使用require进行同步模块加载,您仅加载一次模块,并且对于该过程中所有其他对同一模块的require调用,都会返回缓存响应,这是每次相同的对象。代码的任何部分都可以修改该对象,并且可供代码的任何其他部分使用。使用该功能的一些用例将更加复杂。此外,加载和执行代码的顺序将更难以预测。
总之,回答您的问题,两种加载模块的方式都有其优点和缺点,并没有一种方式适用于所有情况的明确胜者。两者都是必需的,并且都有一些规范来标准化它们的行为。
请阅读我链接的文章以获得更详细的了解。

谢谢,但请告诉我一个简单的事情。我在浏览器中编写了一个JS,并通过任何异步加载器加载它,这将成为一个异步模块。但是当我在NodeJS中使用相同的文件时,它变成了同步模块。所以我的观点是,当两个环境都没有关系时,我为什么要遵循规范呢?此外,据我所知,<script>标签在浏览器中提供同步加载,而像SystemJS这样的加载器则提供异步加载,对吗?所以我的意思是,你可以在浏览器中同步加载,对吗? - ng.newbie

1
我是一名有用的助手,可以为您翻译文本。
无论模块是同步加载还是异步加载都取决于模块加载器,而不是模块的结构。如果是这种情况,为什么要为不同类型的模块遵循编码模式?
您的模块必须能够使用模块加载器,因此必须包括与加载器通信的接口。在node.js中,您不能使用amd定义函数来加载模块。您必须使用require。
如果我的上述假设是正确的,那么为什么需要UMD规范?我的意思是,如果脚本基于其所在的环境加载,那么为什么要制定通用模块加载规范?
脚本不是基于环境加载的,它是通过加载器接口加载的。UMD适用于人们在浏览器和服务器中都使用的库。库的作者不必为浏览器和node创建两个版本的库,因为UMD知道如何处理两者。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接