如何使用RequireJS实现延迟加载?

时间:2012-06-06 08:53:52

标签: javascript backbone.js requirejs js-amd

我们正在使用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模板等。现在发生的事情是,在我的main.js中,所有“顶级”路由器都被加载并初始化;每个顶级路由器都有一组依赖项(模型,视图等),每个依赖项都有自己的依赖项(模板,帮助程序,工具等)。基本上,一个大树结构。

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

有一个“简化的CommonJS包装”解释here,所以我试过了:

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中是否存在寻找require()来电但未实际触发doStuff路线的黑色魔法?
  • 这是解决'按需',延迟加载RequireJS模块和资源的理论上正确的方法吗?
  • 如果使用此表示法,r.js优化器是否仍然可以像宣传的那样工作?

2 个答案:

答案 0 :(得分:50)

这实际上可行吗? RequireJS中是否有黑色magicks寻找对require()的调用而不实际触发doStuff路由?

使用'sugar'语法it uses Function.prototype.toString and a regex提取对require的引用,然后在运行函数之前将它们列为依赖项。基本上,它成为定义的正常样式,其中deps数组作为第一个参数。

因此,它不关心你的require调用的位置,这就是忽略条件语句的原因(这也解释了为什么那些require调用必须使用字符串文字,而不是变量)。 / p>

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

如您所见,使用糖语法不允许条件加载。我能想到的唯一方法就是使用带有一系列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优化器是否仍然可以像宣传的一样工作?

如果您正在使用'sugar'语法,那么是,优化器将正常工作。一个例子:

<强>模块/ test.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优化项目,那么使用糖语法就没有巨大的开销。

答案 1 :(得分:3)

您可能还想查看require-lazy

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

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

在上一个上下文中,mymodulepromise,真实模块将加载get(),并将在then()回调中提供:

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

Require-lazy与r.js集成以自动创建&#34;捆绑&#34;的Javascript文件。它还可以自动处理捆绑包的缓存。有几个例子可以得到一个想法。还有GruntBower集成。