В чем разница между использованием Require.JS и простым созданием <script>
элемента в DOM?
Насколько я понимаю, Require.JS заключается в том, что он предлагает возможность загружать зависимости, но разве это не может быть сделано просто путем создания <script>
элемента, который загружает необходимый внешний файл JS?
Например, предположим, что у меня есть функция doStuff()
, для которой требуется функция needMe()
. doStuff()
находится во внешнем файле do_stuff.js
, а needMe()
находится во внешнем файле need_me.js
.
Делая это способом Require.JS:
define(['need_me'],function(){
function doStuff(){
//do some stuff
needMe();
//do some more stuff
}
});
Для этого нужно просто создать элемент скрипта:
function doStuff(){
var scriptElement = document.createElement('script');
scriptElement.src = 'need_me.js';
scriptElement.type = 'text/javascript';
document.getElementsByTagName('head')[0].appendChild(scriptElement);
//do some stuff
needMe();
//do some more stuff
}
Оба они работают. Однако вторая версия не требует от меня загрузки всей библиотеки Require.js. Функциональной разницы особо не вижу ...
javascript
requirejs
dynamic-script-loading
js-amd
Maxedison
источник
источник
Ответы:
Вот хорошая статья на ajaxian.com о том, зачем ее использовать:
RequireJS: асинхронная загрузка JavaScript
источник
В вашем примере вы создаете тег скрипта асинхронно, что означает, что ваша
needMe()
функция будет вызываться до завершения загрузки файла need_me.js. Это приводит к неперехваченным исключениям, когда ваша функция не определена.Вместо этого, чтобы то, что вы предлагаете, действительно работало, вам нужно сделать что-то вроде этого:
function doStuff(){ var scriptElement = document.createElement('script'); scriptElement.src = 'need_me.js'; scriptElement.type = 'text/javascript'; scriptElement.addEventListener("load", function() { console.log("script loaded - now it's safe to use it!"); // do some stuff needMe(); //do some more stuff }, false); document.getElementsByTagName('head')[0].appendChild(scriptElement); }
Возможно, лучше всего использовать диспетчер пакетов, такой как RequireJS, или использовать стратегию чистого JavaScript, как показано выше. Хотя ваше веб-приложение может загружаться быстрее, вызов функций и функций на сайте будет происходить медленнее, так как это потребует ожидания загрузки ресурсов, прежде чем это действие может быть выполнено.
Если веб-приложение создано как одностраничное приложение, учтите, что люди на самом деле не будут перезагружать страницу очень часто. В этих случаях предварительная загрузка всего поможет ускорить работу при фактическом использовании приложения. В этих случаях вы правы, можно просто загрузить все ресурсы, просто включив теги скрипта в заголовок или тело страницы.
Однако, если вы создаете веб-сайт или веб-приложение, которое следует более традиционной модели, когда происходит переход от страницы к странице, вызывая перезагрузку ресурсов, подход с отложенной загрузкой может помочь ускорить эти переходы.
источник
Некоторые другие очень веские причины, по которым использование RequireJS имеет смысл:
Взято из комментариев rmurphey здесь, в этом Gist .
Слои абстракции могут быть кошмаром для изучения и адаптации, но когда они служат определенной цели и делают это хорошо, это просто имеет смысл.
источник
Вот более конкретный пример.
Я работаю в проекте с 60 файлами. У нас есть 2 разных режима работы.
Загрузите объединенную версию, 1 большой файл. (Производство)
Загрузить все 60 файлов (разработка)
Мы используем загрузчик, поэтому у нас есть только один скрипт на веб-странице
<script src="loader.js"></script>
По умолчанию используется режим №1 (загрузка одного большого объединенного файла). Для запуска в режиме №2 (отдельные файлы) мы устанавливаем какой-нибудь флаг. Это могло быть что угодно. Ключ в строке запроса. В этом примере мы просто делаем это
<script>useDebugVersion = true;</script> <script src="loader.js"></script>
loader.js выглядит примерно так
if (useDebugVersion) { injectScript("app.js"); injectScript("somelib.js"); injectScript("someotherlib.js"); injectScript("anotherlib.js"); ... repeat for 60 files ... } else { injectScript("large-concatinated.js"); }
Скрипт сборки - это просто файл .sh, который выглядит следующим образом
так далее...
Если добавляется новый файл, мы, скорее всего, будем использовать режим №2, так как мы занимаемся разработкой, нам нужно добавить
injectScript("somenewfile.js")
строку в loader.jsПозже для производства мы также должны добавить somenewfile.js в наш сценарий сборки. Шаг, который мы часто забываем, а затем получаем сообщения об ошибках.
При переходе на AMD нам не нужно редактировать 2 файла. Устранена проблема синхронизации loader.js и сценария сборки. Используя
r.js
илиwebpack
он может просто прочитать код для сборкиlarge-concantinated.js
Он также может иметь дело с зависимостями, например, у нас было 2 файла lib1.js и lib2.js, загруженных следующим образом
injectScript("lib1.js"); injectScript("lib2.js");
lib2 требуется lib1. Внутри него есть код, который делает что-то вроде
Но поскольку внедренные скрипты загружаются асинхронно, нет гарантии, что они загрузятся в правильном порядке. Эти 2 сценария не являются сценариями AMD, но, используя require.js, мы можем определить их зависимости.
require.config({ paths: { lib1: './path/to/lib1', lib2: './path/to/lib2', }, shim: { lib1: { "exports": 'lib1Api', }, lib2: { "deps": ["lib1"], }, } });
В нашем модуле, который использует lib1, мы делаем это
define(['lib1'], function(lib1Api) { lib1Api.doSomething(...); });
Теперь require.js будет внедрять скрипты для нас и не будет внедрять lib2, пока lib1 не будет загружена, поскольку мы сказали, что lib2 зависит от lib1. Он также не запустит наш модуль, использующий lib1, пока не загрузятся и lib2, и lib1.
Это делает разработку удобной (без этапа сборки, не беспокоясь о порядке загрузки) и делает производство приятным (нет необходимости обновлять сценарий сборки для каждого добавленного сценария).
В качестве дополнительного бонуса мы можем использовать плагин babel webpack для запуска babel над кодом для старых браузеров, и, опять же, нам не нужно поддерживать этот сценарий сборки.
Обратите внимание, что если бы Chrome (наш любимый браузер) начал поддерживать
import
реальную поддержку, мы, вероятно, переключились бы на него для разработки, но это ничего не изменит. Мы все еще могли бы использовать webpack для создания объединенного файла, и мы могли бы использовать его для запуска babel над кодом для всех браузеров.Все это достигается за счет отказа от тегов скриптов и использования AMD
источник