2012-06-06 1 views
58

Мы создаем нетриверное веб-приложение с использованием Backbone, RequireJS и Handlebars, и хорошо, мне просто интересно. На данный момент каждый из наших моделей Сорта выглядит следующим образом:Как достичь ленивой загрузки с помощью RequireJS?

define(['Backbone', 'js/thing/a', 'js/thing/b', 'js/lib/bob'], function(a, b, bob) { 
    return Backbone.Router.extend({ 
    // stuff here 
    }); 
}); 

где вещь/а, вещь/б оба имеют свою собственную зависимость, например, на шаблоны рулей и т.д. То, что происходит сейчас, что в моем главном .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 рекламу, если вы используете эту нотацию?

ответ

48

Возможно ли это? Есть ли черная магия в RequireJS, которая ищет вызовы, требующие(), без фактического запуска маршрута doStuff?

При использовании «сахар» синтаксис it uses Function.prototype.toString and a regex извлечь ваши ссылки на require, а затем выводит их в качестве зависимостей перед выполнением функции. В основном это обычный стиль определения с массивом deps в качестве первого аргумента.

Из-за этого ему все равно, где ваши вызовы требуют, и поэтому условные операторы игнорируются (это также объясняет, почему вызовы require должны использовать строковый литерал, а не переменную).

Является ли это теоретически правильным способом «по требованию», ленивой загрузкой модулей и ресурсов RequireJS?

Использование синтаксиса сахара не позволяет выполнять условную загрузку, как вы видели. Единственный способ, которым я могу думать с верхней части моей головы, чтобы использовать require вызов с массивом DEPS и обратного вызова:

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, то при использовании синтаксиса сахара нет больших накладных расходов.

3

Вы также можете зарегистрироваться require-lazy.

У этого есть компонент времени выполнения и компонент времени сборки. Компонент исполнения позволяет лениво требовать модуль как (обратите внимание lazy! плагин):

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

В предыдущем контексте mymodule является promise, реальный модуль будет загружен с get() и будут доступны в then() обратного вызова:

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

Требовать-ленивые интегрируется с r.js для автоматического создания «пучки» из JavaScript-файлов. Он также обрабатывает автоматическое переполнение кэша для пакетов. Есть несколько примеров, чтобы получить представление. Существует также Grunt и Bower интеграции.