如何使用 RequireJS 实现延迟加载? [英] How to achieve lazy loading with RequireJS?

查看:23
本文介绍了如何使用 RequireJS 实现延迟加载?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在使用 Backbone、RequireJS 和 Handlebars 构建一个重要的 Web 应用程序,好吧,我只是很好奇.目前,我们的每个模型看起来都像这样:

We're building a non-trival web application using Backbone, RequireJS and Handlebars, and well, I'm just curious. At the moment, each of our models sorta looks like this:

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 中,所有顶级"路由器都被加载和初始化;每个顶级路由器都有一组依赖项(模型、视图等),每个都有自己的依赖项(模板、帮助程序、实用程序等).基本上是一个大树结构.

where thing/a, thing/b both have their own dependencies, for example on Handlebars templates, etc. What happens now is that in my main.js, all of the 'top-level' routers are loaded and initialized; each top-level router has a set of dependencies (models, views, etc) which each have their own dependencies (templates, helpers, utils, etc). Basically, a big tree structure.

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

The problem in this case is that this entire tree is resolved and loaded on page load. I don't mind that per sé, as we'll run it through the optimizer eventually and end up with one big single file (reducing RequireJS to basically a modularization framework). However, I am curious whether you can load stuff like views and templates 'on demand'.

此处解释了简化的 CommonJS 包装",所以我尝试了:

There is the "simplified CommonJS wrapping" explained here, so I tried that:

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

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

However, looking at Chrome's network inspector, it seems that RequireJS - somehow, even without triggering the route that triggers the doStuff handler - still loads the myView dependency. Questions:

  • 这真的可能吗?RequireJS 中是否有黑魔法来查找对 require() 的调用而不实际触发 doStuff 路由?
  • 这是进行按需"延迟加载 RequireJS 模块和资源的理论上正确的方法吗?
  • 如果您使用这种表示法,r.js 优化器是否仍然像宣传的那样工作?
  • Is this actually possible? Are there black magicks in RequireJS that looks for calls to require() without actually triggering the doStuff route?
  • Is this the theoretically correct way of going about 'on-demand', lazy loading of RequireJS modules and resources?
  • Does the r.js optimizer still work as advertised if you use this notation?

推荐答案

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

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

When you use the 'sugar' syntax it uses Function.prototype.toString and a regex to extract your references to require and then lists them as dependencies before running the function. Basically it becomes the normal style of define with an array of deps as the first argument.

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

Because of this, it doesn't care where your require calls are and that's why conditional statements are ignored (it also explains why those require calls have to use a string literal, and not a variable).

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

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

Using the sugar syntax won't allow conditional loading as you've seen. The only way I can think of off the top of my head is to use a require call with an array of deps and a callback:

define(function(require) {
    var module1 = require('module1');

    // This will only load if the condition is true
    if (true) {
        require(['module2'], function(module2) {

        });
    }

    return {};
});

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

Only downside is another nested function but if you're after performance then this is a valid route.

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

如果您使用的是 'sugar' 语法,那么是的,优化器可以正常工作.一个例子:

If you're using the 'sugar' syntax then yes, the optimiser will work fine. An example:

modules/test.js

define(function(require) {
    var $ = require('jquery');
    var _ = require('underscore');

    return {
        bla: true
    }
});

由 r.js 编译后如下所示:

Once compiled by r.js this looks like:

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

    return {
        bla: true
    }
});

总而言之,您可以有条件地加载内容,但正如您所提到的,如果您打算使用 r.js 优化项目,那么仅使用糖语法不会产生巨大的开销.

In conclusion you can load stuff conditionally, but as you mentioned, if you intend to optimise the project with r.js then there isn't a huge overhead in just using the sugar syntax.

这篇关于如何使用 RequireJS 实现延迟加载?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆