Подтвердить что ты не робот

Как достичь ленивой загрузки с помощью RequireJS?

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

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

где вещь /a, вещь/b имеют свои собственные зависимости, например, на шаблонах Handlebars и т.д. Теперь происходит то, что в моем main.js загружаются и инициализируются все маршрутизаторы верхнего уровня; каждый маршрутизатор верхнего уровня имеет набор зависимостей (модели, представления и т.д.), каждый из которых имеет свои собственные зависимости (шаблоны, помощники, утилиты и т.д.). В основном, большая древовидная структура.

Проблема в этом случае заключается в том, что все это дерево разрешено и загружается при загрузке страницы. Я не возражаю против этого, потому что мы запустим его через оптимизатора и в итоге получим один большой отдельный файл (что уменьшит RequireJS до основной платформы модуляции). Тем не менее, мне любопытно, можете ли вы загружать такие вещи, как представления и шаблоны "по запросу".

Существует "упрощенная упаковка CommonJS", объясненная здесь , поэтому я попробовал это:

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 все еще работает, как рекламируется, если вы используете это обозначение?
4b9b3361

Ответ 1

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

Когда вы используете синтаксис "sugar" он использует Function.prototype.toString и регулярное выражение для извлечения ссылок на require, а затем перечисляет их как зависимости перед запуском функции. В основном это обычный стиль определения с массивом deps в качестве первого аргумента.

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

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

Использование синтаксиса сахара не позволит условной загрузки, как вы видели. Единственный способ, с помощью которого я могу думать, это использовать вызов 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, то при использовании синтаксиса сахара не будет огромных накладных расходов.

Ответ 2

Вы также можете проверить 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 интеграция.