如何使用 RequireJS 实现延迟加载



我们正在使用Backbone,RequireJS和Handlebars构建一个非竞争对手的Web应用程序,好吧,我只是好奇。目前,我们的每个模型都如下所示:

define(['Backbone', 'js/thing/a', 'js/thing/b', 'js/lib/bob'], function(a, b, bob) {
  return Backbone.Router.extend({
    // stuff here
  });
});
其中 thing/

a、thing/b 都有自己的依赖项,例如在 Handlebars 模板等上。现在发生的事情是,在我的主.js中,所有"顶级"路由器都被加载和初始化;每个顶级路由器都有一组依赖项(模型、视图等),每个依赖项都有自己的依赖项(模板、帮助程序、实用程序等)。基本上,一个大树结构。

在这种情况下,问题是整个树在页面加载时被解析并加载。我不介意每个sé,因为我们最终将通过优化器运行它,并最终得到一个大的单个文件(将RequireJS简化为基本上是一个模块化框架)。但是,我很好奇您是否可以"按需"加载视图和模板等内容。

这里有解释的"简化的 CommonJS 包装",所以我尝试了:

define(function(require) {
  Backbone = require('Backbone');
  return Backbone.Router.extend({
    doStuff: function() {
      var MyView = require('js/myView');
      new MyView().render();
    }
  });
});

但是,查看Chrome的网络检查器,似乎RequireJS(不知何故,即使没有触发触发doStuff处理程序的路由)仍然加载myView依赖项。问题:

  • 这真的可能吗?RequireJS 中是否存在黑魔法,可以在不实际触发doStuff路由的情况下查找对require()的调用?
  • 这是理论上正确的"按需",延迟加载RequireJS模块和资源的方法吗?
  • 如果您使用此表示法,r.js 优化器是否仍按宣传的那样工作?

这真的可能吗?RequireJS 中是否有黑魔法可以在不实际触发 doStuff 路由的情况下查找对 require() 的调用?

当您使用"sugar"语法时,它使用 Function.prototype.toString 和正则表达式来提取对require的引用,然后在运行函数之前将它们列为依赖项。基本上,它成为定义的正常样式,将 deps 数组作为第一个参数。

因此,它不关心您的 require 调用在哪里,这就是忽略条件语句的原因(这也解释了为什么这些 require 调用必须使用字符串文字,而不是变量)。

这是理论上正确的"按需",延迟加载RequireJS模块和资源的方法吗?

如您所见,使用 sugar 语法不允许条件加载。我能想到的唯一方法是使用带有 deps 数组和回调的 require 调用:

define(function(require) {
    var module1 = require('module1');
    // This will only load if the condition is true
    if (true) {
        require(['module2'], function(module2) {
        });
    }
    return {};
});

唯一的缺点是另一个嵌套函数,但如果您追求性能,那么这是一个有效的路由。

如果您使用此表示法,r.js 优化器是否仍按宣传的那样工作?

如果您使用的是"糖"语法,那么是的,优化器可以正常工作。举个例子:

模块/测试.js

define(function(require) {
    var $ = require('jquery');
    var _ = require('underscore');
    return {
        bla: true
    }
});

一旦由 r 编译.js它看起来像:

define('modules/test', ['require', 'jquery', 'underscore'], function(require) {
    var $ = require('jquery');
    var _ = require('underscore');
    return {
        bla: true
    }
});

总之,你可以有条件地加载东西,但正如你提到的,如果你打算用 r.js 优化项目,那么仅仅使用 sugar 语法就不会有巨大的开销。

您可能还想查看 require-lazy。

它有一个运行时组件和一个构建时组件。运行时组件允许您懒惰地要求模块作为(请注意lazy!插件):

define(["lazy!mymodule"], function(mymodule) {
    ...
});

在前面的上下文中,mymodule是一个 promise,真正的模块将加载get(),并将在then()回调中可用:

mymodule.get().then(function(m) {
    // here m is the real mymodule
});

Require-lazy 与 r.js 集成,以自动创建 Javascript 文件的"捆绑包"。它还处理捆绑包的自动缓存无效化。有几个例子可以得到一个想法。还有Grunt和Bower的整合。

最新更新