Ответ 1
Я думаю, что ваше объяснение немного вводит в заблуждение: в обоих случаях у вас будет вызов require
верхнего уровня с атрибутом data-main
, определяющим файл, чтобы начать процесс запроса разных модулей.
Как правило, вы будете иметь это в своем HTML:
<script data-main="app/config" src="assets/js/libs/require.js"></script>
Затем в обоих случаях у вас будет файл app/config
, который устанавливает вашу конфигурацию (хотя вы можете сделать это непосредственно в HTML) и, что более важно, вызывает require
в ваших модулях:
require.config({
paths: {
jquery: '../assets/js/libs/jquery'
}
});
require(['app']);
Теперь, когда мы добираемся до определения модулей с зависимостями, которые отличаются от этих стилей. В стиле amd вы передаете имена модулей (пути) в виде массива и функцию, которая принимает одинаковое количество аргументов:
app.js
define(['module/first', 'module/second', 'module/third'], function (firstModule, secondModule, thirdModule) {
// use firstModule, secondModule, thirdModule here
});
В упрощенном синтаксисе CommonJS вы просто передаете require
в define
, а затем требуете, какие модули вам нужны:
app.js
define(function(require) {
var firstModule = require('modules/first');
var secondModule = require('modules/second');
var thirdModule = require('modules/third');
// use firstModule, secondModule, thirdModule here
}
Возвращаясь к исходному вопросу, преимущества стиля CommonJS над стилем amd должны быть ясными.
Во-первых, с обычным синтаксисом, если требуется много модулей, очень просто ошибочно присваивать модули неправильным именам переменных. Рассмотрим этот общий случай:
define(['jquery', 'underscore', 'backbone', 'modules/first', 'modules/second', 'modules/third', 'i18n', 'someOtherModule'], function ($, _, Backbone, first, second, third, I18n, someOtherModule) {
// ...
});
Сразу же, вы можете видеть, что когда мы добавляем новый модуль в этот список, мы должны быть очень осторожны, чтобы соответствующий аргумент новой функции появился в нужном месте, иначе мы можем назначить jQuery для Backbone
, и т.д. В некоторых случаях это может создать очень тонкие ошибки, которые трудно отследить.
Теперь рассмотрим синтаксис CommonJS:
define(function(require) {
var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');
var firstModule = require('modules/first');
var secondModule = require('modules/second');
var thirdModule = require('modules/third');
var I18n = require('i18n');
var someOtherModule = require('someOtherModule');
// ...
}
Обратите внимание, что:
- Сопряжение модуля с именем переменной очень ясно.
- Порядок утверждений require не важен, так как имена переменных спариваются отдельно, а не как сопоставление между массивом и функцией.
- Сначала не нужно назначать модули. Они могут быть назначены в любом месте, пока это действительно до того, как модуль действительно используется.
Это всего лишь несколько причин, которые приходят на ум, я уверен, что есть и другие. В принципе, если у вас только одна или две зависимости, любой синтаксис будет работать нормально. Но если у вас сложная сеть зависимостей модулей, синтаксис CommonJS, вероятно, предпочтительнее.
Обратите внимание, что в документах RequireJS они упоминают это небольшое предостережение:
Не все браузеры предоставляют полезные результаты Function.prototype.toString(). По состоянию на октябрь 2011 года браузеры PS 3 и старше Opera Mobile этого не делают. Эти браузеры, скорее всего, нуждаются в оптимизированной сборке модулей для ограничений сети/устройства, поэтому просто создайте с оптимизатором, который знает, как преобразовать эти файлы в форму нормализованного массива зависимостей, такую как оптимизатор RequireJS.
Но это не главная проблема:
Поскольку число браузеров, которые не могут поддерживать это toString(), очень мало, безопасно использовать эти оформленные формы для всех ваших модулей, особенно если вы хотите выстроить имена зависимостей с переменными, которые будут содержать их значения модуля.