【问题标题】:requirejs - Performance of multiple calls to requirerequirejs - 多次调用 require 的性能
【发布时间】:2013-11-10 17:17:46
【问题描述】:

我想知道在具有多个模块的项目中使用 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();
});

require(['jquery','module1','module1','module1','gmaps'], function(jquery, module1,module2,module3,gmaps){
   module1.use();
   module2.use();
   module3.use();
   gmaps.use();
});

换句话说,require 的性能损失是多少,最佳实践是什么。

【问题讨论】:

    标签: javascript performance requirejs amd


    【解决方案1】:

    这里问题的答案是“视情况而定”。我说的是在大型应用程序中使用过 RequireJS 但没有彻底阅读过 RequireJS 代码的人。 (只是指出,了解 RequireJS 内部和内部的人可能会与我解释不同。)require 的成本可以分解为 3 种成本情景:

    1. 如果模块从未被加载,require 从服务器加载文件,执行文件,执行模块的工厂函数并返回对模块的引用。 (从网络加载文件的成本通常比其他成本相形见绌。)

    2. 如果模块已经加载但从未需要,require 执行模块的工厂函数并返回对模块的引用。 (这通常发生在优化的应用程序中。)

    3. 如果模块已经被加载并且需要,require 返回一个对该模块的引用。

    成本方案 1 > 成本方案 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 一次 一个(无数次 - 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();
            [...]
        });
    
        [...]
    });
    

    【讨论】:

      【解决方案2】:

      这取决于你想要什么样的加载行为。

      当您需要尚未需要的模块时,将发出 HTTP 请求以加载所需的模块。如果需要的模块至少被加载过一次,它会存储在 require 的缓存中,所以当你第二次需要该模块时,它将使用缓存的值。

      因此,它可以在延迟加载或急切加载之间进行选择。

      require 试图解决的问题是,每个模块都可以定义它的依赖关系——所以你的第一种方法可能是“最佳实践”。最后,您可能希望使用 r.js 将您的应用程序构建到单个 JS 文件中。

      【讨论】:

      • 在我所描述的上下文中,所有的“使用”功能都需要尽快运行。所以我对延迟加载它们并不直接感兴趣。在第二种方法中,我在想,例如,如果其中一个模块(例如 gmaps)需要更多时间来加载,那么其他模块可能执行得更快(因此可以更快地向用户显示一些 UI 操作)
      • AFAIK,无论您使用哪种方法,在加载所有依赖项之前都不会运行任何代码 - 因此,如果您预先定义所有依赖项,这并不重要。我刚刚意识到我的大部分答案都是假的,因为最终在加载所有依赖项之前没有任何代码会运行。
      【解决方案3】:

      第二种方法在我看来是违背require js的主要目的,即不同程序逻辑的分离。如果您将代码放在一个“模块”中,为什么还要使用 requirejs? 。就性能而言,定义您对性能的定义很重要。如果是您的代码执行速度,那么应该没有明显的差异。加载所有必需的模块后,代码将立即执行。另一方面,如果您所说的性能是指:当代码执行开始时 - 那么显然在第二种方法中,您将对所需代码所在的文件的额外请求导致额外的开销。

      编辑:

      仔细查看问题后,我的答案的第一部分不太适合。代码实际上是在引用外部模块,所以第二个选项并不违背 requirejs 库的目的,实际上是更好的方法,只要结合其依赖项的模块不试图做太多。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-11-29
        • 2012-02-15
        • 1970-01-01
        • 2012-07-25
        • 1970-01-01
        • 1970-01-01
        • 2020-06-08
        相关资源
        最近更新 更多