我想知道在具有多个模块的项目中使用RequireJS的正确方法是什么,关于具有较少依赖性的多个require调用的性能与具有所有依赖性的单个require的性能。
让我们假设一个应用程序,我需要加载一些模块:gmaps, jquery, module1, module2, module3
。某些模块的使用是相当独立的。所以,问题是建议使用以下哪种替代方法(假设此代码是加载到页面中的主要模块):
require(['gmaps'], function(gmaps){
gmaps.use();
});
require(['jquery','module1'], function(jquery, module1){
module1.use();
});
require(['jquery','module2'], function(jquery, module2){
module2.use();
});
require(['jquery','module3'], function(jquery, module3){
module3.use();
});
VS
require(['jquery','module1','module1','module1','gmaps'], function(jquery, module1,module2,module3,gmaps){
module1.use();
module2.use();
module3.use();
gmaps.use();
});
换句话说,require
的性能损失是什么,这是最好的做法。
答案 0 :(得分:6)
这里问题的答案是“这取决于”。我说的是在大型应用程序中使用RequireJS但是不的人彻底阅读了RequireJS的代码。 (只是指出那些从内到外都知道RequireJS内部的人可能会解释与我不同的方式。)require
的成本可以分解为3种成本方案:
如果模块从未加载过,require
从服务器加载文件,执行文件,执行模块的工厂函数并返回对模块的引用。 (从网络加载文件的成本通常使其他成本相形见绌。)
如果模块已加载但从未需要,require
将执行模块的工厂功能并返回对模块的引用。 (这通常发生在优化的应用程序中。)
如果模块已经加载并且需要,require
将返回对模块的引用。
成本方案1&gt; <成本方案2>成本方案3。
首先,让我们考虑每个文件有一个模块的情况。应用程序未优化。我有一个名为module1
的模块,在蓝色的月亮中需要一次。它在主应用程序中的用法可以这样建模:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
module1.use();
[...]
});
即使我不使用该模块,我始终支付成本方案编号1的价格。最好这样做:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
if (rare_condition_happening_once_in_a_blue_moon)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
通过这种方式,我只需支付在蓝色月亮中加载模块一次的价格。
现在,如果我需要反复使用module
怎么办?这可以建模为:
define(["module1", <bunch of other required modules>],
function (module1, <bunch of other modules variables>) {
[...]
for(iterate a gazillion times)
module1.use();
[...]
});
在这种情况下,成本方案编号1支付一次,这就是全部。如果我像这样使用require
:
define([<bunch of required modules>],
function (<bunch of module variables>) {
[...]
for(iterate a gazillion times)
require(["module1"], function (module1) {
module1.use();
});
[...]
});
我支付成本方案编号1一次和 a(数十亿次 - 1)成本方案编号3.在一天结束时,是否应包含module1
define
电话或单独require
电话的要求取决于您的应用的具体情况。
如果使用r.js
或自制优化对应用程序进行了优化,则分析会发生变化。如果应用程序已经过优化,所有模块都在一个文件中,那么每次您在上述情况下支付成本方案1时,您都需要支付成本方案2。
为了完整起见,我将补充一点,如果您不想提前加载模块,可能需要使用require
。
define([<bunch of other required modules>],
function (<bunch of other modules variables>) {
[...]
require(<requirements unknown ahead of time>, function(m1, m2, ...) {
m1.foo();
m2.foo();
[...]
});
[...]
});
答案 1 :(得分:1)
取决于您想要的加载行为。
当您需要尚未需要的模块时,将发出HTTP请求以加载所需的模块。如果所需模块至少已加载一次,则它存储在require的缓存中,因此当您第二次需要该模块时,它将使用缓存的值。
所以,它是懒惰或急切加载之间的选择。
击>
需要解决的问题是,每个模块都可以定义它的依赖关系 - 所以你的第一种方法可能是“最佳实践”。最后,您需要使用r.js将应用程序构建到单个JS文件中。
答案 2 :(得分:1)
在我看来,第二种方法是针对require js的主要目的,即不同程序逻辑的分离。如果将代码放在一个“模块”中,为什么要使用requirejs? 。在性能方面,定义您的性能定义非常重要。如果是代码执行的速度,那么应该没有明显的区别。加载所有必需的模块后,代码将立即执行。另一方面,如果性能的意思是:当代码执行开始时 - 显然在第二种方法中,由于对所需代码所在的文件的额外请求而导致额外的开销。
编辑:
仔细研究这个问题之后,我的答案的第一部分并不合适。代码实际上是引用外部模块,所以第二个选项不是针对requirejs库的目的,只要结合其依赖关系的模块没有尝试做太多,实际上是更好的方法。