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

Why do I need JavaScript module loading and what is the difference between all these loaders?

问题1:

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

问题2:

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

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

有没有一种方法可以让AMD和CJS很好地运行,这样客户端JS文件就可以异步加载,但仍然有CJS语法?

(require.js究竟做了什么?我一辈子都不能在他们网站上的字里行间阅读。)


如果您想为每个页面加载整个JavaScript源代码,当然,可以将其编译成一个文件。如果根据用户采取的操作或已加载的页面加载不同的代码,请使用AMD加载的模块。另一种选择是列出一组脚本标记,当然一次只能加载一个,可能需要一段时间。

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

1
2
3
4
5
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作为依赖项的模块使用此路径。当使用模块存根或调试某些模块的版本时,这对于在测试时轻松切换也很有用。

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


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

如果你有一个20000行的文件,你只需要600行就可以启动和运行所有的东西(假设所有的东西都是模块化和异步的,使用任何模式来管理资源),那么如果你为核心程序服务并根据需要进行扩展,你就可以节省半秒或更长的时间。(或在延迟计时器上,为彼此密切相关的大量功能提供服务)。

下载所花费的总时间更高。使用的HTTP连接总数更高。但是,使页面对用户可见所需的时间较短。向页面添加基本功能所需的时间较短。然后,额外的功能可以在加载和初始化之后,或者按照用户的请求及时地进行流式处理,在这两种情况下,只要您流式处理的代码集中在做这一件事上,并且不需要调用其他六个依赖项,那么请求和功能添加之间的时间是将是最小的。

基本上,Requirejs使用承诺系统。

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

总的来说,如果你有一个所有文件都很小的系统,那么页面上JS的总重量就很小,你只需要几百行就可以完成页面上所有你想做的事情……另外,您知道您的所有依赖项在哪里,您在服务器上有一个系统来确保它们的顺序是正确的,等等(另外,您有很好的文档,或者您是唯一一个接触此代码的人,并且您每天都生活在其中)。…那么做你正在做的事完全没有错。

如果编译时间超过了您发出的HTTP请求的数量,您可能根本看不到任何不同。但是对于总长度为数万(或数十万)行的应用程序来说,在任何一个页面上只需要该功能的一小部分,从页面加载到应用程序"准备好"供用户进行基本交互之间的感知时间上可以大幅度节省。


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

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

如果您不需要这些好处或编程加载提供的其他好处,那么您只需使用普通的标签,让它们同步加载即可。