如何使用RequireJS实现延迟加载?
我们正在使用Backbone,RequireJS和Handlebars构build一个非trival的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中,所有的“顶级”路由器都被加载和初始化。 每个顶级路由器都有一组依赖关系(模型,视图等),每个依赖关系都有自己的依赖关系(模板,帮助器,utils等)。 基本上,一个大树的结构。
在这种情况下的问题是整个树被parsing并加载页面加载。 我不介意这样做,因为我们将通过优化器最终运行它,并最终得到一个大的单个文件(将RequireJS简化为模块化框架)。 不过,我很好奇你是否可以按需求加载视图和模板等内容。
这里解释了“简化的CommonJS包装”,所以我试过了:
define(function(require) { Backbone = require('Backbone'); return Backbone.Router.extend({ doStuff: function() { var MyView = require('js/myView'); new MyView().render(); } }); });
然而,看着Chrome的networking检查员,看起来RequireJS – 即使不触发触发doStuff处理程序的路由 – 也不知何故,仍会加载myView
依赖项。 问题:
- 这实际上是可能的吗? RequireJS中是否存在黑色的磁条,在没有实际触发
doStuff
path的情况下寻找require()
调用? - 这是理论上正确的方式来进行“按需”,延迟加载RequireJS模块和资源?
- 如果使用这种表示法,r.js优化器是否仍然像广告一样工作?
这实际上是可能的吗? RequireJS中是否存在黑色的磁条,在没有实际触发doStuffpath的情况下寻找require()的调用?
当你使用'sugar'语法时, 它使用Function.prototype.toString
和一个正则expression式来提取你require
的引用,然后在运行该函数之前将它们列为依赖关系。 基本上它成为第一个参数deps数组定义的正常样式。
正因为如此,它不关心你的需求调用的地方,这就是为什么条件语句被忽略(这也解释了为什么那些require
调用必须使用string,而不是variables)。
这是理论上正确的方式来进行“按需”,延迟加载RequireJS模块和资源?
使用糖语法将不允许有条件的加载,如你所见。 我能想到的唯一办法就是用一个deps和一个callback数组来调用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优化器是否仍然像广告一样工作?
如果你使用'糖'语法,那么是的,优化器将正常工作。 一个例子:
模块/ 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来优化项目,那么在使用糖语法时没有太大的开销。
你也可能想要退房懒惰 。
它有一个运行时组件和一个构build时间组件。 运行时组件允许你懒惰地需要一个模块(注意lazy!
插件):
define(["lazy!mymodule"], function(mymodule) { ... });
在前面的上下文中, mymodule
是一个promise ,真正的模块将被加载get()
,并将在then()
callback中可用:
mymodule.get().then(function(m) { // here m is the real mymodule });
需要懒惰的集成与r.js自动创build“捆绑”的JavaScript文件。 它还自动处理捆绑的caching清除。 有几个例子可以得到一个想法。 还有Grunt和Bower集成。