为什么我需要加载JavaScript模块,所有这些加载器之间有什么区别?

时间:2012-10-02 20:04:01

标签: javascript amd commonjs

问题1

为什么我需要在网页中异步加载我的JavaScript文件?我可以在服务器端看到它的基本原理,但如果我知道我需要在客户端加载的所有文件,为什么我不应该将所有源文件连接成1个文件并在页面加载时加载?第一个初始页面加载是否如此重要,以至于由于检索每个JS文件的延迟而导致未来的操作可能会变慢?

问题2

假设问题1的答案是我需要单独加载JS文件:

AMD异步加载每个JS文件,CommonJS同步加载。服务器端加载需要CJS(如果我没有弄错的话,这就是Node.js的工作方式)。 AMD似乎更适合客户。因此,在客户端中使用CJS的唯一原因是与服务器共享代码。

有没有办法让AMD和CJS发挥得很好,以便客户端JS文件可以异步加载但仍然具有CJS语法?

(究竟是什么需要.js呢?我不能为我的生活在他们网站上的行之间阅读。)

3 个答案:

答案 0 :(得分:3)

您不需要“异步”或通过某些自定义加载程序加载javascript文件。以下是异步加载或自定义加载可能带来好处的一些原因:

  • 当通常不需要javascript文件时,您可能希望根据需要而不是一直加载它
  • 当初始页面显示不需要javascript文件且您想要最大化页面首次显示的速度时
  • 当您想要控制加载javascript文件的时间时
  • 当您根据某些条件决定是否加载javascript文件时(例如,如果从CDN加载失败,您可以从备份位置加载)
  • 当您希望脚本加载与其他内容并行进行而不是一个接一个地序列化时

如果您不需要任何这些好处或程序加载提供的其他好处,那么您可以使用普通的<script>标记并让它们同步加载。

答案 1 :(得分:3)

只是连接文件的部分问题不是下载所花费的时间,而是在每个页面上编译的时间。

如果您有一个20,000行文件,并且您只需要其中600行来启动和运行(假设所有内容都是模块化和异步编写的,使用任何模式来管理资源),如果您为核心程序提供服务并按需扩展(或延迟计时器,提供彼此密切相关的大块功能),那么您将自己保存半秒或更长时间。< / p>

下载的总时间更长 使用的HTTP连接总数更高 但是,使页面对用户可见所需的时间较短 向页面添加基本功能所需的时间较短 然后,可以在加载和初始化之后流入额外的功能,或者按照用户的请求即时流动,并且在两种情况下,只要您流入的代码专注于执行该功能事情,并没有要求六个其他依赖项,请求和添加功能之间的时间将是最小的。

RequireJS基本上使用了承诺系统。

它允许您预先声明依赖关系,并在处理完所有依赖关系之后提交要实现的代码(作为回调)。
如果这些依赖项具有任何依赖关系,那么 它们 将不会被初始化,直到它们的依赖项被加载。
如果你只是想加载它并且顺序不重要,那么你不需要给它依赖。

总体道德是,如果你的系统所有文件都很小,页面上JS的整体重量非常小,你只需要几百行来完成你想要的一切。 ......而且,你知道所有的依赖关系在哪里,你在服务器上有一个系统,以确保它们的顺序正确,等等(加上你有很好的文档,或者你是唯一接触过这段代码的人,你每天都住在里面...... ......那么做你正在做的事情并没有什么不妥。

如果编译时间超过您发出的HTTP请求数,则可能看不到任何差异。 但是对于长达数十(或数百)行的整体应用程序,在任何一个页面上只需要该功能的一小部分,在页面加载和当页面加载之间的感知时间方面可以节省很多。应用程序“准备好”用户进行基本交互。

答案 2 :(得分:3)

如果您想为每个页面加载整个javascript源,请确保将其编译为一个文件。如果根据用户执行的操作加载不同的代码,或者根据加载的页面加载不同的代码,请使用AMD加载的模块。另一种选择是列出一堆脚本标签,当然一次只能加载一个,可能需要一段时间。

AMD不是一个特定的库,它实际上是一个标准,用于加载你提到的大多数加载器使用的javascript模块。这意味着它们都使用类似的语法来定义和加载模块。他们正在考虑将AMD作为ECMA脚本规范的一部分。它的用处是您还可以定义依赖项,因此如果您的代码需要运行jQuery,您可以将其列为依赖项,并将其加载到模块名称空间中。

define( [ 'jquery' ], function ( $ ) {
    // use jquery in here without clouding up the global namespace

    return {}; // return your module for use in a different module or whatever
};

在此示例中,在下载jquery模块之前,将不会运行已定义模块中的代码。然后,它将jquery模块作为参数$直接注入到新定义的模块中。

现在,您可以将代码整齐地整理到包含模块的文件中。您的所有模块都不会使全局命名空间变得模糊。您的所有依赖项肯定会在模块运行之前加载(没有加载竞争条件错误的依赖代码片段)。

另一个优点是您可以设置加载程序为同一模块使用不同的路径,因此您可以将jquery模块的路径定义为“https://ajax.googleapis.com/ajax/ libs / jquery / 1.8.2 / jquery.min.js'代码中的一个位置,即使它几乎可以在每个模块中使用。现在当我需要将我的jquery版本更新到1.8.3时,我可以简单地在我的代码中的一个位置更改路径,并且它将使用此路径用于使用jquery作为依赖项的每个模块。当您使用模块存根或调试某些模块的版本时,这对于在测试时轻松切换也很有用。

现在,小型项目不一定需要这样做。然而,你的项目越大,这种类型的加载就越有意义。