it-swarm.com.de

Was ist der Unterschied zwischen Require.js und dem einfachen Erstellen eines <script> -Elements im DOM?

Was ist der Unterschied zwischen der Verwendung von Require.JS AMD, indem einfach ein <script>-Element im DOM erstellt wird?

Nach meinem Verständnis von Require.JS können Abhängigkeiten geladen werden. Kann dies jedoch nicht einfach durch Erstellen eines <script>-Elements erfolgen, das die erforderliche externe JS-Datei lädt?

Nehmen wir beispielsweise an, ich habe die Funktion doStuff(), für die die Funktion needMe() erforderlich ist. doStuff() befindet sich in der externen Datei do_stuff.js, während needMe() in der externen Datei need_me.js enthalten ist.

Auf diese Weise den Require.JS-Weg:

define(['need_me'],function(){
    function doStuff(){
        //do some stuff
        needMe();
        //do some more stuff
    }
});

Dazu einfach ein Skriptelement erstellen:

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
}

Beide arbeiten. Bei der zweiten Version muss ich jedoch nicht die gesamte Require.js-Bibliothek laden. Ich sehe keinen funktionalen Unterschied ...

137
maxedison

Hier ist der Nizza-Artikel auf ajaxian.com, warum es verwendet wird:

RequireJS: Asynchrones JavaScript-Laden

  • eine Art # include/import/required
  • fähigkeit, geschachtelte Abhängigkeiten zu laden
  • benutzerfreundlichkeit für Entwickler, aber durch ein Optimierungstool unterstützt, das die Bereitstellung erleichtert
43
Sarfraz

Welche Vorteile bietet Require.JS im Vergleich zur einfachen Erstellung eines Elements im DOM? 

In Ihrem Beispiel erstellen Sie das Skript-Tag asynchron. Das heißt, Ihre Funktion needMe() würde vorher aufgerufen, und die need_me.js-Datei wird vollständig geladen. Dies führt zu nicht erfassten Ausnahmen, bei denen Ihre Funktion nicht definiert ist.

Um zu erreichen, dass das, was Sie vorschlagen, tatsächlich funktioniert, müssen Sie Folgendes tun:

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);

}

Es ist möglicherweise am besten, einen Paket-Manager wie RequireJS oder eine reine JavaScript-Strategie zu verwenden, wie oben gezeigt. Während Ihre Webanwendung möglicherweise schneller lädt, ist das Aufrufen von Funktionen und Features auf der Website langsamer, da das Laden von Ressourcen vor dem Ausführen der Aktion abgewartet werden muss.

Wenn eine Webanwendung als Einzelseitenanwendung erstellt wird, sollten Sie bedenken, dass Benutzer die Seite nicht sehr oft neu laden. In diesen Fällen würde das Vorladen von alles dazu beitragen, das Erlebnis schneller erscheinen zu lassen, wenn die Anwendung tatsächlich using ist. In diesen Fällen haben Sie Recht, Sie können einfach alle Ressourcen laden, indem Sie die Skript-Tags in den Kopf oder Körper der Seite einfügen.

Wenn Sie jedoch eine Website oder eine Webanwendung erstellen, die einem traditionelleren Modell folgt, bei dem von Seite zu Seite übergegangen wird und Ressourcen neu geladen werden, kann ein langsamer Ladevorgang diese Übergänge beschleunigen.

52
jmort253

Einige andere sehr wichtige Gründe, warum die Verwendung von RequireJS sinnvoll ist:

  1. Das Verwalten eigener Abhängigkeiten fällt bei umfangreichen Projekten schnell auseinander.
  2. Sie können so viele kleine Dateien haben, wie Sie möchten, und Sie müssen sich keine Sorgen um Abhängigkeiten oder Ladereihenfolge machen.
  3. RequireJS ermöglicht das Schreiben einer gesamten, modularen App, ohne das Fensterobjekt zu berühren. 

Genommen aus rmurpheys Kommentaren hier in diesem Gist .

Abstraktionsebenen können ein Albtraum sein, an dem man lernen und sich anpassen kann, aber wenn sie einem Zweck dient und es gut macht, macht es nur Sinn.

9

Hier ist ein konkreteres Beispiel.

Ich arbeite in einem Projekt mit 60 Dateien. Wir haben zwei verschiedene Betriebsmodi.

  1. Laden Sie eine verkettete Version (1 große Datei). (Produktion)

  2. Laden Sie alle 60 Dateien (Entwicklung)

Wir verwenden einen Loader, also haben wir nur ein Skript auf der Webseite 

<script src="loader.js"></script>

Der Standardwert ist Modus 1 (Laden der einen großen verketteten Datei). Um den In-Modus # 2 (separate Dateien) auszuführen, setzen wir ein Flag. Es könnte alles sein. Ein Schlüssel in der Abfragezeichenfolge. In diesem Beispiel machen wir das einfach

<script>useDebugVersion = true;</script>
<script src="loader.js"></script>

loader.js sieht ungefähr so ​​aus

if (useDebugVersion) {
   injectScript("app.js");
   injectScript("somelib.js");
   injectScript("someotherlib.js");
   injectScript("anotherlib.js");
   ... repeat for 60 files ...
} else {
   injectScript("large-concatinated.js");
}

Das Build-Skript ist nur eine .sh-Datei, die so aussieht

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

usw...

Wenn eine neue Datei hinzugefügt wird, verwenden wir wahrscheinlich Modus # 2, da wir gerade mit der Entwicklung beginnen. Wir müssen eine injectScript("somenewfile.js")-Zeile zu loader.js hinzufügen

Später müssen wir für die Produktion auch somenewfile.js zu unserem Build-Skript hinzufügen. Ein Schritt, den wir oft vergessen und dann Fehlermeldungen erhalten.

Wenn Sie zu AMD wechseln, müssen wir nicht zwei Dateien bearbeiten. Das Problem der Synchronisierung von loader.js und des Build-Skripts wird beseitigt. Mit r.js oder webpack kann der Code einfach gelesen werden, um large-concantinated.js zu erstellen.

Es kann auch mit Abhängigkeiten umgehen, zum Beispiel hatten wir zwei Dateien lib1.js und lib2.js, die so geladen wurden

injectScript("lib1.js");
injectScript("lib2.js");

lib2 benötigt lib1. Es hat Code im Inneren, der so etwas macht

lib1Api.installPlugin(...);

Da die eingespritzten Skripts asynchron geladen werden, kann nicht garantiert werden, dass sie in der richtigen Reihenfolge geladen werden. Diese beiden Skripte sind keine AMD-Skripte, aber mithilfe von „requir.js“ können wir ihre Abhängigkeiten erkennen

require.config({
    paths: {
        lib1: './path/to/lib1',
        lib2: './path/to/lib2',
    },
    shim: {
        lib1: {
            "exports": 'lib1Api',
        },
        lib2: {
            "deps": ["lib1"],
        },
    }
});

In unserem Modul, das lib1 verwendet, tun wir dies

define(['lib1'], function(lib1Api) {
   lib1Api.doSomething(...);
});

Nun werden die Skripte von requir.js eingespritzt, und lib2 wird erst injiziert, wenn lib1 geladen wurde, seit wir gesagt haben, dass lib2 von lib1 abhängt. Unser Modul, das lib1 verwendet, wird erst gestartet, wenn lib2 und lib1 geladen wurden.

Dies macht die Entwicklung schön (kein Erstellungsschritt, keine Sorge um die Reihenfolge beim Laden) und es macht die Produktion schön (kein Erstellungsskript für jedes hinzugefügte Skript erforderlich).

Als zusätzlichen Bonus können wir das babel-Plugin von webpack verwenden, um babel über den Code für ältere Browser auszuführen. Auch dieses Build-Skript muss nicht beibehalten werden. 

Wenn Chrome (unser bevorzugter Browser) anfing, import für real zu unterstützen, würden wir wahrscheinlich für die Entwicklung zu dem wechseln, was jedoch nichts ändern würde. Wir könnten immer noch webpack verwenden, um eine verkettete Datei zu erstellen, und wir könnten damit babel über den Code für alle Browser laufen.

All dies wird erreicht, indem keine Skript-Tags und AMD verwendet werden

0
gman