Яка різниця між Require.js та просто створенням елемента <script> у DOM? [зачинено]


138

Яка різниця між використанням Require.JS amd просто створенням <script>елемента в DOM?

Моє розуміння Require.JS полягає в тому, що він пропонує можливість завантажувати залежності, але чи можна це зробити не просто, створивши <script>елемент, який завантажує необхідний зовнішній файл JS?

Наприклад, припустимо, що у мене є функція doStuff(), яка вимагає функції needMe(). doStuff()знаходиться у зовнішньому файлі do_stuff.js, тоді needMe()як у зовнішньому файлі need_me.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. Я не бачу жодної функціональної різниці ...


1
як щодо кешування браузера, чи вимагає його вимагати?
Мухаммед Умер

Я знову відкриваю це, тому що прошу різницю між двома дуже схожими речами. На нього можна відповісти об'єктивно, і я не бачу, де думка пов'язана з цим.
RamenChef

Відповіді:


43

Ось приємна стаття на ajaxian.com щодо того, для чого його використовувати:

RequireJS: Асинхронне завантаження JavaScript

  • якесь # включати / імпортувати / вимагати
  • можливість завантаження вкладених залежностей
  • простота використання для розробника, але потім підкріплена інструментом оптимізації, який допомагає розгортати

2
Я читав їх, але тепер, коли я більше замислююся над цим, я розумію, що ідеї про вкладені залежності неможливо досягти, просто написавши теги <script>. Дякую.
maxedison

37
"простота використання для розробника" не могла бути далі від істини. Це, безумовно, має круту криву навчання для вас і всіх, хто прийде працювати в цьому проекті.
Сахат Ялкабов

3
@TwilightPony Я вважаю себе не таким яскравим і вимагаючим насправді не було важкою справою для мене. Це позбавляє вас від необхідності турбуватися про залежності і прискорює сторінку. Ваш код стає більш вбудованим у програмування на стороні сервера в тому, як ви заявляєте про свої залежності, які я особисто вважаю освіжаючими та простими. Синтаксис був мінімальним і замикався на закриття дизайну, а потім встановлює дорожню карту для виробництва, щоб легко поєднати ваші сценарії. На додаток до налагодження - це як статичні оголошення. Не впевнений, що простіше, ніж це. Набагато складніше інший шлях, як я зробив інший шлях.
Джейсон Себрінг

Я борюся. Особливо з модулями, які намагаються приєднатися до глобальних об’єктів. (Реагувати модулі) ...
позолочено

1
Зауваження на цій сторінці насправді залишили у мене відчуття, що слід бігти і не вимагати. Особливо той, що знаходиться внизу, який посилається на stevesouders.com/tests/require.php
Дейв Кантер

52

Які переваги пропонує Require.JS порівняно з просто створенням елемента в DOM?

У вашому прикладі ви створюєте тег сценарію асинхронно, а це означає, що ваша 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, як показано вище. Хоча ваш веб-додаток може завантажуватися швидше, виклик функціональності та функцій на сайті буде повільніше, оскільки це вимагатиме очікування завантаження ресурсів до того, як ця дія може бути виконана.

Якщо веб-додаток побудовано як односторінковий додаток, то врахуйте, що люди насправді не перезавантажують сторінку дуже часто. У цих випадках попереднє завантаження всього допоможе зробити так, щоб ця робота здавалася швидшою при фактичному використанні програми. У цих випадках ви маєте рацію, ви можете просто завантажити всі ресурси, просто включивши теги скриптів у голову або тіло сторінки.

Однак, якщо створити веб-сайт або веб-додаток, який слід більш традиційній моделі, коли один перехід зі сторінки на сторінку, що спричиняє перезавантаження ресурсів, підхід для ледачого завантаження може допомогти прискорити ці переходи.


10

Деякі інші дуже наголошені причини, чому використання RequireJS має сенс:

  1. Управління власними залежностями швидко розпадається на значні проекти.
  2. Ви можете мати стільки маленьких файлів, скільки вам потрібно, і не потрібно турбуватися про відстеження залежностей або порядку завантаження.
  3. RequireJS дає можливість написати цілу модульну програму, не торкаючись об’єкта вікна.

Взяте з коментарів rmurphey тут, у цій історії .

Шари абстракції можуть бути кошмаром, щоб навчитися та пристосуватися, але коли це служить цілі та робить це добре, це просто має сенс.


9
Вам все одно доведеться керувати всіма тими, хто вимагає та визначає оператори, файли конфігурації, зіткнення з іншими системами та бібліотеками, які не реалізували специфікацію AMD тощо. Я намагався використовувати Require.JS в проекті node-webkit та Require.JS боровся зі мною на кожному кроці ... На противагу цьому, просто замовляючи сценарії певним чином ... Звичайно, ти отримуєш ледачий навантаження з Require.JS, саме тому я намагався змусити його працювати. :)
jmort253

Я повністю згоден з @ jmort253, на початку це була боротьба, але зараз мені це дуже подобається. Усі три бали вірні! І AMDifying бібліотека не повинна бути такою складною ... або використовувати лайф.
Легенди

0

Ось більш конкретний приклад.

Я працюю над проектом із 60 файлами. У нас є 2 різних режими його роботи.

  1. Завантажте з'єднану версію, 1 великий файл. (Виробництво)

  2. Завантажте всі 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-файл, який виглядає приблизно так

cat > large-concantinated.js app.js somelib.js someotherlib.js anotherlib.js

тощо ...

Якщо буде доданий новий файл, ми, швидше за все, будемо використовувати режим №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. У ньому є код, який робить щось подібне

lib1Api.installPlugin(...);

Але оскільки введені сценарії завантажуються асинхронно, немає гарантії, що вони завантажуватимуться у правильному порядку. Ці 2 сценарії не є сценаріями AMD, але, використовуючи requ.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(...);
});

Тепер requ.js введе сценарії для нас, і він не введе lib2, поки не буде завантажений lib1, оскільки ми сказали, що lib2 залежить від lib1. Він також не запустить наш модуль, який використовує lib1, поки не завантажуються і lib2, і lib1.

Це робить розробку приємною (без кроку збирання, не турбуючись про порядок завантаження), і робить виробництво приємним (не потрібно оновлювати сценарій збірки для кожного доданого сценарію).

Як додатковий бонус, ми можемо використовувати плагін для веб-упаковки webpack для запуску бабеля над кодом для старих браузерів, і знову нам також не потрібно підтримувати цей сценарій складання.

Зауважте, що якби Chrome (наш вибір браузера) почав підтримувати importреально, ми, ймовірно, переходимо до цього для розробки, але це насправді нічого не змінить. Ми ще можемо використовувати webpack для створення зв'язаного файлу, і ми можемо використовувати його для запуску бабеля над кодом для всіх браузерів.

Все це отримується за допомогою не використання тегів скриптів та використання AMD

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.