为什么require.js似乎在初始页面加载时加载了所有模块?

6
我正在开发一个使用requirejs的单页面backbone应用程序。今天我将它部署到测试服务器上时,发现初始页面加载时间长达20秒,因为它需要获取所有的脚本。
我猜测是因为我在定义模块时使用了依赖数组,如下所示:
define([
    'ui',
    'models/user',
    'collections/campaigns',
    'collections/groups',
    'collections/keywords',
    'collections/inboxes',
    'collections/templates',
    'collections/contacts',
    'router'
], function (Ui, UserDetails, Campaigns, Groups, Keywords, Inboxes, Templates, Contacts, Router) {

    return {
        start: function () {
            // ...
            // initialize and start app
            // ...
        }
    }
});

我认为这意味着当主应用程序模块被加载时,由于每个模块都使用此方法,因此将加载每个其他脚本。我随后更改了获取模块的方法,通过在需要时直接调用require('...')来获取它们,如下所示:
define(function (require) {
    return Backbone.Router(function () {
        // ...
        // route initializtion etc
        // ...

        inbox: function (routeVar) {
            var InboxView = require('InboxView');
            this.inboxView = new InboxView();
            // render view etc
        }
    });
});

然而让我惊讶的是,当我再次运行应用程序并检查Chrome开发者控制台的网络选项卡时,我发现应用程序仍在获取所有模块,并且页面加载时间与之前相同。

我完全错过了什么吗?因为我原本以为每次调用require时脚本都会被获取。难道不是这样吗?

1个回答

6
为了异步加载AMD模块,您必须调用require并提供一个函数回调,在请求的模块加载完成后将调用该回调函数:
require(['InboxView'], function(InboxView) {
  // Do something with InboxView here...
});

您提供的示例代码在同步方式下调用了require('InboxView')。由于您使用了“sugar”语法,RequireJS将检查您的代码,找到任何对require()的同步调用,并将这些依赖项添加到模块的顶级依赖列表中,从而使您获得以下结果:
define(['require', 'InboxView'], function (require) {
  return Backbone.Router(function () {
    // ...
    // route initializtion etc
    // ...

    inbox: function (routeVar) {
        var InboxView = require('InboxView');
        this.inboxView = new InboxView();
        // render view etc
    }
  });
});

因此,你看到所有模块都立即加载的原因是如此。
在require中添加异步回调即可。同时,如果你想一想,如果RequireJS等待加载InboxView模块直到路由触发,而没有使用require调用阻塞直到加载完成,那么你的代码会怎样工作呢? :)

1
我其实以为它会在加载脚本时阻塞,谢谢你的信息,我会进一步研究的。 - jcvandan
谢谢你的回复,按照你建议的进行异步请求解决了我的问题。现在我的初始页面加载时间大大缩短了。非常感谢! - jcvandan
"['require', 'InboxView']" 的意思是什么?我从未见过这样的东西。谢谢。 - Vlad Nicula
要求使用require告诉requireJS为模块提供一个正确作用域的实例,以便它可以使用该实例来要求更多的模块。如果您使用诸如多版本支持之类的功能,则适当的作用域非常重要,因此require会加载所请求的模块的正确版本。在这个特定的实例中,所需模块的列表是由requireJS自动生成的,因为使用了sugar语法 - rharper
@dormisher,您能详细说明一下您的最终解决方案是什么吗?我已经尝试了上面的代码,但是a)它不起作用,因为没有语法require('InboxView', function(InboxView) {}),b)从概念上讲,不存在所谓的“同步”require调用。所有的require调用都是异步的。 - T Nguyen
@TNguyen 抱歉,在第一个示例中,'InboxView' 应该被包裹在 [] 中。已修复。 - rharper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接