AMD / Require JS - 如何仅按需加载文件

时间:2013-12-30 20:14:55

标签: backbone.js requirejs lazy-loading amd js-amd

我有一些AMD / Require.js问题。我对模块化的js和AMD都很陌生,所以如果有人能帮我解决这个问题会很棒。

假设我的系统有2个不同的区域,定义为模块(“define()”函数 - 我正在使用Backbone,顺便说一句)

  • 图书
    • BookItemView.js
    • BookModel.js
    • BookCollection.js
  • DVDS
    • DvdItemView.js
    • DvdModel.js
    • DvdCollection.js

我注意到,如果用户当前正在访问网站的“图书”部分,则DVD部分中的文件也包含在Require.js中。我有以下问题:

  • 是否有某种方法只包含与活动网站部分相关的文件?在某些情况下,用户不想看DVD列表,甚至不允许这样做。我想让服务器不要发出不必要的HTTP请求。有没有机会使用Require.js?

任何想法都会很好。

4 个答案:

答案 0 :(得分:3)

这是可能的,但在很大程度上取决于您如何构建JS应用程序。另外,我假设你在这里有一个Backbone应用程序。不同的框架有不同的方法。

例如,您可能会看到app.js,如下所示:

define([
    'DvdItemView', 'DvdModel', 'DvdCollection', 
    'BookItemView', 'BookModel', 'BookCollection'
], function(DvdView, DvdModel, DvdCol, BookView, BookModel, BookCol) {

   // router declarations go here

});

由于您根据上述模块“定义”此模块,因此在运行路由器代码之前始终会加载它们。正如@alexndm指出的那样,如果你在这上面运行r.js,你实际上可以将所有模块合并为一个。

然而,正如您所提到的,一旦应用程序达到一定大小,您想要的是根据用户与之交互的内容来延迟加载不同的部分。这更像是一个应用程序问题,而RequireJS在这方面只能帮助你。我认为最好的方法是在路由器中。

routes: {
    '/books': 'booksList',
    '/books/:id': 'booksDetail',
    '/dvds': 'dvdList',
    '/dvds/:id': 'dvdDetail'
},

booksList: function() {
    if (!booksDepsLoaded) {
        // Here we go and load the appropriate files
        require(['BooksArea'], function(BooksArea) {
            // BooksArea.Model, BooksArea.Collection, etc...
            // do stuff to render a book list..
        })
    }
},

...

这是非常天真的伪代码。您可能希望编写一些通用代码来处理仍需要加载依赖项的路由,以及错误处理等。

要掌握的重要概念是,您需要在应用程序/路由器启动之前定义路由 - 然后您需要异步代码来处理提取模块。

答案 1 :(得分:3)

查看require-lazy,这是一个在运行时和编译时都插入的小库(r.js)我写的就是按你的要求去做。基本用法是:

(来自main.js脚本:)

define(["lazy!modules/books", "lazy!modules/dvds"], function(books, dvds) {
    ...
});

modules/booksmodules/dvds脚本与往常一样。上面定义函数中的booksdvds变量实际上是实际模块的 promises 。他们自己的模块预先加载。然后,在main.js中的某个位置,代码决定显示哪个视图:

if( view === "books" ) {
    books.get().then(function(realBooks) {
       ...
    });
}
else if( view === "dvds" ) {
    dvds.get().then(function(realDvds) {
       ...
    });
}

它也支持gruntbower

答案 2 :(得分:2)

实际上可以通过稍微不同的项目结构来实现这一点。

詹姆斯伯克有一个回购详细说明如何在这里进行,https://github.com/requirejs/example-multipage-shim

基本思想是你有多个“main.js”文件可以为你网站的不同区域加载依赖项。

因此,在您的情况下,您可能会有main-booksmain-dvd个文件。

在不同领域的HTMl中,只需加载两个区域所需的通用模块,然后加载特定的主文件......

require(['./js/common'], function (common) {
    require(['app/main-books']);
});

希望有所帮助!

答案 3 :(得分:1)

在生产中使用require.js时,建议运行r.js http://requirejs.org/docs/optimization.html

它的作用是:   - 将相关脚本组合到构建层中,并通过UglifyJS(默认值)或Closure Compiler(使用Java时的选项)缩小它们。   - 通过内联@import引用的CSS文件并删除注释来优化CSS。

这意味着所有脚本将被连接成一个文件,并且不会有任何额外的http请求。