Wie füge ich eine JavaScript-Datei in eine andere JavaScript-Datei ein?

5194

Gibt es in JavaScript etwas Ähnliches wie @importin CSS, mit dem Sie eine JavaScript-Datei in eine andere JavaScript-Datei einfügen können?

Alec Smart
quelle
82
@ Daniel, ich möchte keinen AJAX-Aufruf verwenden.
Alec Smart
13
Warum nicht die importierte Datei vor der anderen deklarieren, die sie benötigt, indem Sie einfach geordnete scriptTags verwenden?
Falsarella
6
@Claudiu Das würde nicht helfen, etwas zu importieren , aber es sollte auch funktionieren. Wenn Sie eine JS-Datei haben, die von einer anderen JS-Datei abhängt, deklarieren Sie zuerst die Skript-Tags der Abhängigkeitsdateien, damit die Abhängigkeiten der letzteren bereits geladen sind. Wenn Sie eine Situation haben, in der dies nicht möglich ist, sollten die Antworten hier hilfreich sein.
Falsarella
1
Was ist der praktische Vorteil davon? In beiden Fällen wird die von der Javascript-Datei abhängige Codebasis nicht geladen und funktioniert auf keinen Fall, wenn sie nicht geladen wird!
Ciasto Piekarz

Antworten:

4472

Die alten Versionen von JavaScript hatten keinen Import, enthielten oder erforderten, so dass viele verschiedene Ansätze für dieses Problem entwickelt wurden.

Seit 2015 (ES6) verfügt JavaScript jedoch über den Standard für ES6-Module zum Importieren von Modulen in Node.js, der auch von den meisten modernen Browsern unterstützt wird .

Erstellen Sie zur Kompatibilität mit älteren Browsern Tools wie Webpack und Rollup und / oder Transpilations-Tools wie Babel verwendet werden.

ES6-Module

ECMAScript (ES6) -Module werden in Node.js seit Version 8.5 mit dem --experimental-modulesFlag und seit mindestens Node.js Version 13.8.0 ohne Flag unterstützt. So aktivieren Sie „ESM“ (V. Node.js der vorherigen Commonjs-Stil Modulsystem [ „CJS“]) Sie entweder "type": "module"in package.jsonoder die Dateien die Erweiterung geben .mjs. (Ebenso können Module, die mit dem vorherigen CJS-Modul von Node.js geschrieben wurden, benannt werden, .cjswenn Ihre Standardeinstellung ESM ist.)

Verwenden von package.json:

{
    "type": "module"
}

Dann module.js:

export function hello() {
  return "Hello";
}

Dann main.js:

import { hello } from './module.js';
let val = hello();  // val is "Hello";

Mit hätten .mjsSie module.mjs:

export function hello() {
  return "Hello";
}

Dann main.mjs:

import { hello } from './module.mjs';
let val = hello();  // val is "Hello";

ECMAScript-Module in Browsern

Browser unterstützen seit Safari 10.1, Chrome 61, Firefox 60 und Edge 16 das direkte Laden von ECMAScript-Modulen (keine Tools wie Webpack erforderlich). Überprüfen Sie die aktuelle Unterstützung bei caniuse . Die .mjsErweiterung von Node.js muss nicht verwendet werden . Browser ignorieren Dateierweiterungen für Module / Skripte vollständig.

<script type="module">
  import { hello } from './hello.mjs'; // Or it could be simply `hello.js`
  hello('world');
</script>
// hello.mjs -- or it could be simply `hello.js`
export function hello(text) {
  const div = document.createElement('div');
  div.textContent = `Hello ${text}`;
  document.body.appendChild(div);
}

Lesen Sie mehr unter https://jakearchibald.com/2017/es-modules-in-browsers/

Dynamische Importe in Browsern

Durch dynamische Importe kann das Skript nach Bedarf andere Skripte laden:

<script type="module">
  import('hello.mjs').then(module => {
      module.hello('world');
    });
</script>

Weitere Informationen finden Sie unter https://developers.google.com/web/updates/2017/11/dynamic-import

Node.js erfordern

Der ältere CJS-Modulstil, der in Node.js immer noch weit verbreitet ist, ist das module.exports/require system.

// mymodule.js
module.exports = {
   hello: function() {
      return "Hello";
   }
}
// server.js
const myModule = require('./mymodule');
let val = myModule.hello(); // val is "Hello"   

Es gibt andere Möglichkeiten für JavaScript, externe JavaScript-Inhalte in Browser aufzunehmen, für die keine Vorverarbeitung erforderlich ist.

AJAX wird geladen

Sie können ein zusätzliches Skript mit einem AJAX-Aufruf laden und dann evalzum Ausführen verwenden. Dies ist der einfachste Weg, der jedoch aufgrund des JavaScript-Sandbox-Sicherheitsmodells auf Ihre Domain beschränkt ist. Die Verwendung evalöffnet auch die Tür zu Fehlern, Hacks und Sicherheitsproblemen.

Laden holen

Wie bei Dynamic Imports können Sie ein oder mehrere Skripte mit einem fetchAufruf laden , indem Sie Versprechen verwenden, um die Ausführungsreihenfolge für Skriptabhängigkeiten mithilfe der Fetch Inject- Bibliothek zu steuern :

fetchInject([
  'https://cdn.jsdelivr.net/momentjs/2.17.1/moment.min.js'
]).then(() => {
  console.log(`Finish in less than ${moment().endOf('year').fromNow(true)}`)
})

jQuery wird geladen

Die jQuery- Bibliothek bietet Ladefunktionen in einer Zeile :

$.getScript("my_lovely_script.js", function() {
   alert("Script loaded but not necessarily executed.");
});

Dynamisches Laden von Skripten

Sie können dem HTML-Code ein Skript-Tag mit der Skript-URL hinzufügen. Dies ist eine ideale Lösung, um den Overhead von jQuery zu vermeiden.

Das Skript kann sich sogar auf einem anderen Server befinden. Darüber hinaus wertet der Browser den Code aus. Das <script>Tag kann entweder in die Webseite <head>eingefügt oder kurz vor dem schließenden </body>Tag eingefügt werden .

Hier ist ein Beispiel, wie dies funktionieren könnte:

function dynamicallyLoadScript(url) {
    var script = document.createElement("script");  // create a script DOM node
    script.src = url;  // set its src to the provided URL

    document.head.appendChild(script);  // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}

Diese Funktion fügt <script>am Ende des Kopfabschnitts der Seite ein neues Tag hinzu, in dem diesrc Attribut auf die URL festgelegt wird, die der Funktion als erster Parameter zugewiesen wird.

Beide Lösungen werden in JavaScript Madness: Dynamic Script Loading erläutert und veranschaulicht .

Erkennen, wann das Skript ausgeführt wurde

Nun gibt es ein großes Problem, über das Sie Bescheid wissen müssen. Dies bedeutet, dass Sie den Code remote laden . Moderne Webbrowser laden die Datei und führen Ihr aktuelles Skript weiter aus, da sie alles asynchron laden, um die Leistung zu verbessern. (Dies gilt sowohl für die jQuery-Methode als auch für die manuelle Methode zum Laden dynamischer Skripte.)

Wenn Sie diese Tricks direkt verwenden, können Sie Ihren neu geladenen Code in der nächsten Zeile, nachdem Sie ihn zum Laden aufgefordert haben, nicht verwenden , da er noch geladen wird.

Zum Beispiel: my_lovely_script.jsenthält MySuperObject:

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined

Dann laden Sie die schlagende Seite neu F5. Und es funktioniert! Verwirrend...

Was tun?

Nun, Sie können den Hack verwenden, den der Autor in dem Link vorschlägt, den ich Ihnen gegeben habe. Zusammenfassend lässt sich sagen, dass Personen, die es eilig haben, ein Ereignis verwenden, um eine Rückruffunktion auszuführen, wenn das Skript geladen wird. So können Sie den gesamten Code mithilfe der Remote-Bibliothek in die Rückruffunktion einfügen. Zum Beispiel:

function loadScript(url, callback)
{
    // Adding the script tag to the head as suggested before
    var head = document.head;
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;

    // Then bind the event to the callback function.
    // There are several events for cross browser compatibility.
    script.onreadystatechange = callback;
    script.onload = callback;

    // Fire the loading
    head.appendChild(script);
}

Dann schreiben Sie den Code, den Sie verwenden möchten, nachdem das Skript in eine Lambda-Funktion geladen wurde :

var myPrettyCode = function() {
   // Here, do whatever you want
};

Dann führen Sie das alles aus:

loadScript("my_lovely_script.js", myPrettyCode);

Beachten Sie, dass das Skript möglicherweise ausgeführt wird, nachdem das DOM geladen wurde oder vorher, je nachdem, ob der Browser und ob Sie die Zeile eingefügt haben script.async = false;. Es gibt einen großartigen Artikel über das Laden von Javascript im Allgemeinen, in dem dies diskutiert wird.

Zusammenführung / Vorverarbeitung des Quellcodes

Wie oben in dieser Antwort erwähnt, verwenden viele Entwickler in ihren Projekten Build- / Transpilations-Tools wie Parcel, Webpack oder Babel, mit denen sie die kommende JavaScript-Syntax verwenden, Abwärtskompatibilität für ältere Browser bieten, Dateien kombinieren, minimieren, Code-Aufteilung usw. durchführen

e-satis
quelle
130
Nein, aber jemand, der etwas so Fortgeschrittenes wie Rhino verwendet oder diese Frage nicht stellt.
E-Satis
192
Um vollständig zu sein, gibt es einen dritten Weg: In bestimmten Lösungen können Sie, wenn Sie beide Javascript-Dateien steuern, nur eine riesige Javascript-Datei erstellen, die den Inhalt beider Dateien kombiniert.
Kröte
20
Sollte nicht "document.createElement (" my_lovely_script.js ");" im Beispiel sei "document.createElement (" script ")"?
Russell Silva
14
Wie öffnet eval die Tür für Hacks, wenn Sie Ihren Code ausführen?
Vince Panuccio
6
Ihre Antwort erfordert einige Änderungen für den IE ( onreadystatechangeEreignis und die readyStateEigenschaft). Das dynamische Laden von Skripten profitiert auch nicht von den Preload-Scannern des Browswers. Empfehlen Sie diesen HTML5Rocks-Artikel: html5rocks.com/de/tutorials/speed/script-loading
ruhong
570

Wenn jemand etwas Fortgeschritteneres sucht, probieren Sie RequireJS aus . Sie erhalten zusätzliche Vorteile wie Abhängigkeitsverwaltung, bessere Parallelität und Vermeidung von Doppelarbeit (dh mehr als einmaliges Abrufen eines Skripts).

Sie können Ihre JavaScript-Dateien in "Module" schreiben und sie dann als Abhängigkeiten in anderen Skripten referenzieren. Oder Sie können RequireJS als einfache Lösung für dieses Skript verwenden.

Beispiel:

Abhängigkeiten als Module definieren:

some-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

     //Your actual script goes here.   
     //The dependent scripts will be fetched if necessary.

     return libraryObject;  //For example, jQuery object
});

Implementation.js ist Ihre "Haupt" -JavaScript-Datei, die von some-dependency.js abhängt

require(['some-dependency'], function(dependency) {

    //Your script goes here
    //some-dependency.js is fetched.   
    //Then your script is executed
});

Auszug aus der GitHub README:

RequireJS lädt einfache JavaScript-Dateien sowie definierte Module. Es ist für die Verwendung im Browser optimiert, einschließlich in einem Web Worker, kann jedoch auch in anderen JavaScript-Umgebungen wie Rhino und Node verwendet werden. Es implementiert die API für asynchrone Module.

RequireJS verwendet einfache Skript-Tags zum Laden von Modulen / Dateien, sodass ein einfaches Debuggen möglich sein sollte. Es kann also einfach zum Laden vorhandener JavaScript-Dateien verwendet werden Sie es Ihrem vorhandenen Projekt hinzufügen können, ohne Ihre JavaScript-Dateien neu schreiben zu müssen.

...

John Strickler
quelle
1
@aaaidan: MattDmos Grund und es stützt sich auf eine externe Bibliothek, die sich im Gegenzug auf die akzeptierte Antwort stützt.
David Mulder
1
Um require.js zu überwinden, ist Angular js das neueste, das stabiler und einfacher zu verwenden ist, zusammen mit anderen verbindlichen und umfangreichen HTML-Funktionen.
Zeeshan
5
-1: Diese Abstraktionen - "some_dependency" - sind wirklich schlecht, wobei Indizes zu Verwirrung führen. Ich habe Schwierigkeiten zu verstehen, wie ein funktionierendes Codebeispiel aussieht. Wenn der Autor ein Arbeitsbeispiel liefern würde, wäre fast jeder in der Lage, es auf seine Bedürfnisse zuzuschneiden und zu verallgemeinern.
Tegiri Nenashi
1
funktioniert nicht gut mit MVC und
Skriptbündelung
1
'Hinzufügen .. ohne dass Sie Ihre JavaScript-Dateien neu schreiben müssen'; cool, aber wie genau? Cur. Antwort schlägt vor, ein solches 'require' (nicht 'requirejs'?) zum Hauptskript hinzuzufügen + ein solches 'define' zu jeder abhängigen Datei, ja? Aber das IST umgeschrieben, also was nicht umgeschrieben? -Rest des Codes seit RequireJS lässt jede Datei wie gewohnt globale Defs machen? -macht es? Ich habe es gerade versucht, + (vergessen?) <Script src = " requirejs.org/docs/release/2.2.0/comments/require.js "> </ script>, dann 'requirejs ([' GoogleDrive.com/host / ..',.. weibl., Funktion (a, b) {mycode}) ': Firebug sagt, dass jeder abhängige geladene ABER seine Defs nicht in mycode & after definiert sind.
Destiny Architect
195

Es tatsächlich ist eine Möglichkeit , eine JavaScript - Datei zu laden nicht asynchron, so dass Sie die Funktionen in Ihrer neu geladenen Datei rechts enthalten verwenden könnte es nach dem Laden, und ich denke , dass es in allen Browsern funktioniert.

Sie müssen für jQuery.append()das <head>Element Ihrer Seite Folgendes verwenden:

$("head").append('<script type="text/javascript" src="' + script + '"></script>');

Diese Methode hat jedoch auch ein Problem: Wenn in der importierten JavaScript-Datei ein Fehler auftritt, meldet Firebug (und auch Firefox Error Console und Chrome Developer Tools ) seinen Platz falsch. Dies ist ein großes Problem, wenn Sie Firebug zum Verfolgen verwenden JavaScript-Fehler viel runter (ich tue). Firebug kennt die neu geladene Datei aus irgendeinem Grund einfach nicht. Wenn also ein Fehler in dieser Datei auftritt, wird gemeldet, dass er in Ihrer HTML- Hauptdatei aufgetreten ist , und Sie werden Probleme haben, den wahren Grund für den Fehler herauszufinden.

Aber wenn das für Sie kein Problem ist, sollte diese Methode funktionieren.

Ich habe tatsächlich ein jQuery-Plugin namens $ .import_js () geschrieben , das diese Methode verwendet:

(function($)
{
    /*
     * $.import_js() helper (for JavaScript importing within JavaScript code).
     */
    var import_js_imported = [];

    $.extend(true,
    {
        import_js : function(script)
        {
            var found = false;
            for (var i = 0; i < import_js_imported.length; i++)
                if (import_js_imported[i] == script) {
                    found = true;
                    break;
                }

            if (found == false) {
                $("head").append('<script type="text/javascript" src="' + script + '"></script>');
                import_js_imported.push(script);
            }
        }
    });

})(jQuery);

Alles, was Sie tun müssen, um JavaScript zu importieren, ist:

$.import_js('/path_to_project/scripts/somefunctions.js');

Ich habe auch einen einfachen Test dafür bei Beispiel gemacht .

Es enthält eine main.jsDatei im Haupt-HTML und dann das Skript, main.jsmit $.import_js()dem eine zusätzliche Datei namens aufgerufen wird included.js, die diese Funktion definiert:

function hello()
{
    alert("Hello world!");
}

Und direkt nach dem Einschließen included.jswird die hello()Funktion aufgerufen und Sie erhalten die Warnung.

(Diese Antwort ist eine Antwort auf den Kommentar von e-satis).

Kipras
quelle
Ich versuche diese Methode, arbeite aber nicht für mich. Das Element wird einfach nicht im Head-Tag angezeigt.
Websites
16
@ juanpastas - verwenden Sie jQuery.getScript, auf diese Weise müssen Sie sich nicht um das Schreiben des Plugins kümmern ...
MattDMo
6
Hmm, laut diesem Artikel führt das Anhängen eines scriptElements an headdazu, dass es asynchron ausgeführt wird, es sei denn, das asyncist speziell auf eingestellt false.
Flimm
1
Sollte die Skriptvariable keine HTML-Entitäten codiert haben? Wenn der Link das enthält ", wird der Code
unterbrochen
1
@ Flimm Sehr geehrter Herr, ich und mein Team danken für Ihren Kommentar und ich persönlich schulde Ihnen ein Bier von gleichem Geld, wenn wir uns jemals persönlich treffen
Alex
155

Eine andere Möglichkeit, die meiner Meinung nach viel sauberer ist, besteht darin, eine synchrone Ajax-Anfrage zu stellen, anstatt ein <script>Tag zu verwenden. So behandelt auch Node.js.

Hier ist ein Beispiel mit jQuery:

function require(script) {
    $.ajax({
        url: script,
        dataType: "script",
        async: false,           // <-- This is the key
        success: function () {
            // all good...
        },
        error: function () {
            throw new Error("Could not load script " + script);
        }
    });
}

Sie können es dann in Ihrem Code verwenden, wie Sie normalerweise ein Include verwenden würden:

require("/scripts/subscript.js");

Und Sie können in der nächsten Zeile eine Funktion aus dem erforderlichen Skript aufrufen:

subscript.doSomethingCool(); 
Ariel
quelle
1
Gute Lösung, das Head Include ist leider asynchron, die Ajax-Lösung funktioniert.
Matteo Conta
17
Wie bereits erwähnt, erledigt requirejs.org dies und verfügt über einen Pre-Compiler, der js-Dateien zusammenfügt, damit sie schneller geladen werden. Vielleicht möchten Sie es überprüfen.
Ariel
2
Ich konnte es debuggen, indem ich diese Anweisung am Ende der Datei für Chrome hinzufügte: // @ sourceURL = view_index.js
Todd Vance
11
Leider asynchron: false ist in jQuery jetzt veraltet. Könnte in Zukunft brechen, also würde ich vermeiden.
Quadratmeter
3
@katsh Wir verwenden hier keine jqXHR-Objekte. Ihr Zitat scheint Ihren vorherigen Kommentar, der async: falseangeblich veraltet ist, nicht zu stützen. Es ist nicht! Wie in Ihrem Zitat angegeben, handelt es sich nur um jqXHR-bezogene Inhalte.
Zero3
101

Es gibt eine gute Nachricht für Sie. Sehr bald können Sie problemlos JavaScript-Code laden. Es wird eine Standardmethode zum Importieren von Modulen mit JavaScript-Code und wird Teil des Kern-JavaScript selbst sein.

Sie müssen nur schreiben import cond from 'cond.js';, um ein condaus einer Datei benanntes Makro zu laden cond.js.

Sie müssen sich also weder auf ein JavaScript-Framework verlassen noch explizit Ajax- Aufrufe tätigen.

Beziehen auf:

Imdad
quelle
12
require / import on the jsfile hat in den kommenden Jahren viel zu lange gedauert. (IMO).
Rwheadon
6
@rwheadon ja scheint entsetzlich, dass dies nicht Teil der Sprache ist! Wie die Leute etwas erledigen, ist mir ein Rätsel!
Ich bin
@ jonny-leeds Auch ohne das integrierte Laden von Modulen ist JavaScript im Browser so flexibel, dass wir eine Bibliothek wie RequireJS für unsere Modulverwaltung implementieren können.
Keen
8
Mitte 2015 - Noch nicht in einem Browser implementiert, developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
scape
ja, du hast recht. Jetzt fühle ich mich langsam schlecht dafür :(. Thouh, einmal in allen Browsern implementiert, wird dies eine großartige Funktion sein, die in Javascript integriert ist.
Imdad
96

Es ist möglich, ein JavaScript-Tag dynamisch zu generieren und es aus einem anderen JavaScript-Code an ein HTML-Dokument anzuhängen. Dadurch wird eine gezielte JavaScript-Datei geladen.

function includeJs(jsFilePath) {
    var js = document.createElement("script");

    js.type = "text/javascript";
    js.src = jsFilePath;

    document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");
Svitlana Maksymchuk
quelle
8
@ e-satis - Eigentlich ist dies ein Vorteil, ein Synchronisierungsskript würde blockieren. Pferde für Kurse, aber 9 mal in 10 möchten Sie die nicht blockierende Option.
Annakata
@Svitlana - Skriptelemente, die so erstellt wurden, sind asynchron. Derzeit könnte dies als Ausnutzung einer Lücke angesehen werden, so dass es möglicherweise nicht zukunftssicher ist. Ich habe in keinem Standard etwas gesehen, das dies klarstellt.
Annakata
Eigentlich nehme ich es zurück, ich habe bemerkt, dass Sie eher am Körper als am Kopf hängen.
Annakata
@annakata: Was ist der Unterschied? Übrigens, Yahoo schlägt vor, Skript-Tags am Ende des Körpers hinzuzufügen, damit beim dynamischen Anhängen nichts daran falsch ist.
Svitlana Maksymchuk
7
@ e-satis asynchron ist gut, weil es Ihre Seite nicht einfriert. Verwenden Sie Rückruf, um benachrichtigt zu werden, wenn es fertig istjs.onload = callback;
Vitim.us
74

Anweisung importist in ECMAScript 6.

Syntax

import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;
Draupnie
quelle
... wird jedoch laut Kompatibilitätstabelle auf der von Ihnen verlinkten Seite bisher von keinem Browser unterstützt.
Zero3
6
Sie können jetzt ES6-Code schreiben und ihn mit Babel.js ( babeljs.io ) auf ein beliebiges aktuelles Modulsystem (CommonJS / AMD / UMD) kompilieren
Jeremy Harris
@ Zero3 Anscheinend ist der neue IE (Edge) der einzige
Julian Avar
im Jahr 2019 unterstützt IE dies immer noch in keiner Form. Warum muss Microsoft so gegen die Benutzerfreundlichkeit sein?
GreySage
61

Vielleicht können Sie diese Funktion verwenden, die ich auf dieser Seite gefunden habe. Wie füge ich eine JavaScript-Datei in eine JavaScript-Datei ein? ::

function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';

    head.appendChild(script)
}
Arnaud Gouder de Beauregard
quelle
5
Sollte nützlich sein, um hinzuzufügenscript.onload = callback;
Vitim.us
@SvitlanaMaksymchuk Also, wenn ich nicht benutze var, wird die Variable global sein?
Francisco Corrales Morales
@ FranciscoCorrales ja.
Christopher Chiche
Es endet global mit oder ohne var :)
Vedran Maricevic.
54

Hier ist eine synchrone Version ohne jQuery :

function myRequire( url ) {
    var ajax = new XMLHttpRequest();
    ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
    ajax.onreadystatechange = function () {
        var script = ajax.response || ajax.responseText;
        if (ajax.readyState === 4) {
            switch( ajax.status) {
                case 200:
                    eval.apply( window, [script] );
                    console.log("script loaded: ", url);
                    break;
                default:
                    console.log("ERROR: script not loaded: ", url);
            }
        }
    };
    ajax.send(null);
}

Beachten Sie, dass der Server allow-originin seiner Antwort einen Header festlegen muss, damit diese domänenübergreifend funktioniert .

heinob
quelle
Hervorragende Funktion! Lädt das JavaScript, bevor zusätzliches JS nach dem Text geschrieben wird. Sehr wichtig beim Laden mehrerer Skripte.
tfont
3
@heinob: Was kann ich tun, damit es domänenübergreifend funktioniert? (Laden des Skripts von http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js)
user2284570
@ user2284570: Wenn Sie der Eigentümer der fremden Domäne sind: Setzen Sie in der Serverantwort den Header "allow-origin". Wenn Sie nicht der Besitzer sind: nichts. Es tut uns leid! Das ist eine herkunftsübergreifende Politik.
Heinob
2
@ user2284570: Ich verstehe Ihren Kommentar so, dass Sie nicht der Eigentümer der Domain sind, von der Sie das Skript laden möchten. In diesem Fall können Sie ein Skript nur über ein eingefügtes <script>Tag laden , nicht über XMLHttpRequest.
Heinob
2
Wenn Sie dies in Firefox verwenden möchten (z. B. für Imacros-Skripte), fügen Sie diese Zeile oben in die Datei ein:const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
Kwestion
49

Ich habe gerade diesen JavaScript-Code geschrieben (unter Verwendung von Prototype for DOM Manipulation):

var require = (function() {
    var _required = {};
    return (function(url, callback) {
        if (typeof url == 'object') {
            // We've (hopefully) got an array: time to chain!
            if (url.length > 1) {
                // Load the nth file as soon as everything up to the
                // n-1th one is done.
                require(url.slice(0, url.length - 1), function() {
                    require(url[url.length - 1], callback);
                });
            } else if (url.length == 1) {
                require(url[0], callback);
            }
            return;
        }
        if (typeof _required[url] == 'undefined') {
            // Haven't loaded this URL yet; gogogo!
            _required[url] = [];

            var script = new Element('script', {
                src: url,
                type: 'text/javascript'
            });
            script.observe('load', function() {
                console.log("script " + url + " loaded.");
                _required[url].each(function(cb) {
                    cb.call(); // TODO: does this execute in the right context?
                });
                _required[url] = true;
            });

            $$('head')[0].insert(script);
        } else if (typeof _required[url] == 'boolean') {
            // We already loaded the thing, so go ahead.
            if (callback) {
                callback.call();
            }
            return;
        }

        if (callback) {
            _required[url].push(callback);
        }
    });
})();

Verwendungszweck:

<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
    require(['foo.js','bar.js'], function () {
        /* Use foo.js and bar.js here */
    });
</script>

Inhalt: http://gist.github.com/284442 .

Nornagon
quelle
7
jrburke schrieb dies als RequireJS. Github: requirejs.org/docs/requirements.html
Mike Caron
Wird das geladene Skript dadurch nicht außerhalb des Bereichs platziert, in dem require () aufgerufen wird? Scheint, als ob eval () der einzige Weg ist, dies im Rahmen zu tun. Oder gibt es einen anderen Weg?
Trusktr
44

Hier ist die verallgemeinerte Version, wie Facebook dies für den allgegenwärtigen Like-Button tut:

<script>
  var firstScript = document.getElementsByTagName('script')[0],
      js = document.createElement('script');
  js.src = 'https://cdnjs.cloudflare.com/ajax/libs/Snowstorm/20131208/snowstorm-min.js';
  js.onload = function () {
    // do stuff with your dynamically loaded script
    snowStorm.snowColor = '#99ccff';
  };
  firstScript.parentNode.insertBefore(js, firstScript);
</script>

Wenn es für Facebook funktioniert, funktioniert es für Sie.

Der Grund, warum wir nach dem ersten scriptElement anstelle von headoder suchen, bodyist, dass einige Browser kein Element erstellen, wenn es fehlt, aber wir haben garantiert ein scriptElement - dieses. Lesen Sie mehr unter http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .

Dan Dascalescu
quelle
3
Verdammt schön! Einige der Methoden funktionieren auch hier, aber unter einer dynamischen Einstellung funktioniert dies am besten.
tfont
Ich habe Ihr Skript erweitert, um die Veröffentlichung zu beseitigen
Kamil Dąbrowski
39

Wenn Sie in reinem JavaScript wollen, können Sie verwenden document.write.

document.write('<script src="myscript.js" type="text/javascript"></script>');

Wenn Sie die jQuery-Bibliothek verwenden, können Sie die $.getScriptMethode verwenden.

$.getScript("another_script.js");
Venu immadi
quelle
8
würde document.write nicht alles andere entfernen?
Eisa Adil
30

Sie können Ihre Skripte auch mit PHP zusammenstellen :

Datei main.js.php:

<?php
    header('Content-type:text/javascript; charset=utf-8');
    include_once("foo.js.php");
    include_once("bar.js.php");
?>

// Main JavaScript code goes here
Calmarius
quelle
16
Klingt so, als ob es darum geht, dies alles im Frontend in Javascript zu halten
Ariel
1
Vielen Dank, dass Sie daran erinnert haben. Sie können auch PHP <script> -Tags in Ihren HTML-Header schreiben lassen, damit die benötigten js-Dateien (und nur diese) geladen werden.
Rolf
29

Die meisten der hier gezeigten Lösungen implizieren eine dynamische Belastung. Ich suchte stattdessen nach einem Compiler, der alle abhängigen Dateien zu einer einzigen Ausgabedatei zusammenfügt. Genauso wie Less / Sass- Präprozessoren sich mit der CSS @import-Regel befassen . Da ich nichts Anständiges dieser Art fand, schrieb ich ein einfaches Tool, um das Problem zu lösen.

Hier ist also der Compiler https://github.com/dsheiko/jsic , der $import("file-path")den angeforderten Dateiinhalt sicher ersetzt. Hier ist das entsprechende Grunt- Plugin: https://github.com/dsheiko/grunt-jsic .

Im jQuery-Hauptzweig verketten sie einfach atomare Quelldateien zu einer einzigen, beginnend mit intro.jsund endend mitouttro.js . Das passt nicht zu mir, da es keine Flexibilität beim Design des Quellcodes bietet. Überprüfen Sie, wie es mit jsic funktioniert:

src / main.js

var foo = $import("./Form/Input/Tel");

src / Form / Input / Tel.js.

function() {
    return {
          prop: "",
          method: function(){}
    }
}

Jetzt können wir den Compiler ausführen:

node jsic.js src/main.js build/mail.js

Und holen Sie sich die kombinierte Datei

build / main.js

var foo = function() {
    return {
          prop: "",
          method: function(){}
    }
};
Dmitry Sheiko
quelle
2
Seit diesem Beitrag habe ich eine viel bessere Lösung gefunden - den CommonJS-Modul-Compiler - github.com/dsheiko/cjsc. Sie können also einfach CommonJs- oder NodeJs-Module schreiben und aufeinander zugreifen, ohne sie in isolierten Bereichen zu belassen. Die Vorteile: Keine Notwendigkeit für mehrere HTTP-Anforderungen, die sich auf die Leistung auswirken Sie müssen Ihren Modulcode nicht manuell umbrechen - es liegt in der Verantwortung des Compilers (bessere Lesbarkeit des Quellcodes). Sie benötigen keine externen Bibliotheken. Es ist kompatibel mit UMD- und NodeJs Module (z. B. können Sie jQuery, Backbone als Module adressieren, ohne ihren Code zu berühren)
Dmitry Sheiko
26

Wenn Sie zum Laden der JavaScript-Datei die Funktionen aus der importierten / enthaltenen Datei verwenden möchten , können Sie auch ein globales Objekt definieren und die Funktionen als Objektelemente festlegen. Zum Beispiel:

global.js

A = {};

file1.js

A.func1 = function() {
  console.log("func1");
}

file2.js

A.func2 = function() {
  console.log("func2");
}

main.js

A.func1();
A.func2();

Sie müssen nur vorsichtig sein, wenn Sie Skripte in eine HTML-Datei aufnehmen. Die Reihenfolge sollte wie folgt sein:

<head>
  <script type="text/javascript" src="global.js"></script>
  <script type="text/javascript" src="file1.js"></script>
  <script type="text/javascript" src="file2.js"></script>
  <script type="text/javascript" src="main.js"></script>
</head>
Adem İlhan
quelle
22

Dies sollte tun:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
tggagne
quelle
5
Das evalist, was daran falsch ist. Aus Crockford : " Ist evalböse. Die evalFunktion ist die am häufigsten missbrauchte Funktion von JavaScript. Vermeiden Sie sie. evalHat Aliase. Verwenden Sie den FunctionKonstruktor nicht . Übergeben Sie keine Zeichenfolgen an setTimeoutoder setInterval." Wenn Sie sein "JavaScript: The Good Parts" nicht gelesen haben, gehen Sie jetzt raus und machen Sie es. Sie werden es nicht bereuen.
MattDMo
13
@MattDMo "Jemand sagte, es sei schlecht" ist nicht wirklich ein Argument.
Casey
4
@emodendroket Ich nehme an, Sie wissen nicht, wer Douglas Crockford ist.
MattDMo
13
@MattDMo Ich bin mir völlig bewusst, wer er ist, aber er ist ein Mensch, kein Gott.
Casey
2
@tggagne: Was kann ich tun, damit es domänenübergreifend funktioniert? (Laden des Skripts von http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js)
user2284570
21

Verwenden Sie ein Skript, um es vor dem Hochladen zu verketten, anstatt es zur Laufzeit einzuschließen.

Ich benutze Kettenräder (ich weiß nicht, ob es andere gibt). Sie erstellen Ihren JavaScript-Code in separaten Dateien und fügen Kommentare hinzu, die von der Sprockets-Engine als Includes verarbeitet werden. Für die Entwicklung können Sie Dateien nacheinander einfügen und dann für die Produktion zusammenführen ...

Siehe auch:

JMawer
quelle
Browserify ist weitaus beliebter als Sprockets.
Dan Dascalescu
18

Ich hatte ein einfaches Problem, aber die Antworten auf diese Frage verwirrten mich.

Ich musste eine Variable (myVar1) verwenden, die in einer JavaScript-Datei (myvariables.js) in einer anderen JavaScript-Datei (main.js) definiert war.

Dafür habe ich wie folgt gemacht:

Laden Sie den JavaScript-Code in der HTML-Datei in der richtigen Reihenfolge, zuerst myvariables.js, dann main.js:

<html>
    <body onload="bodyReady();" >

        <script src="myvariables.js" > </script>
        <script src="main.js" > </script>

        <!-- Some other code -->
    </body>
</html>

Datei: myvariables.js

var myVar1 = "I am variable from myvariables.js";

Datei: main.js

// ...
function bodyReady() {
    // ...
    alert (myVar1);    // This shows "I am variable from myvariables.js", which I needed
    // ...
}
// ...

Wie Sie gesehen haben, hatte ich eine Variable in einer JavaScript-Datei in einer anderen JavaScript-Datei verwendet, aber ich musste keine in eine andere aufnehmen. Ich musste nur sicherstellen, dass die erste vor der zweiten JavaScript-Datei geladene JavaScript-Datei und die Variablen der ersten JavaScript-Datei in der zweiten JavaScript-Datei automatisch zugänglich sind.

Das hat mir den Tag gerettet. Ich hoffe das hilft.

Manohar Reddy Poreddy
quelle
Das Problem mit dieser Antwort ist, dass es nicht so etwas ist import. Sie benötigen eine HTML-Datei, um Inhalte von einer JS-Datei in eine andere zu übertragen.
Cannicide
Sehr richtig. Das ist es, was einige andere Antworten als Lösung haben. Ich hatte jedoch zwei JS-Dateien, eine sollte die Variablen anderer JS verwenden. Keine node.js, next.js, express.js usw., also funktioniert der Import ODER die Anforderung nicht, hatte nur einfache .js-Dateien.
Manohar Reddy Poreddy
Verständlich ist jedoch die Frage, ob eine Javascript-Datei in eine andere Datei selbst importiert werden soll und nicht nur über eine HTML-Datei auf ihre Variablen zugegriffen werden soll. Angenommen, Sie erstellen Funktionen für eine Schaltfläche und verwenden drei verschiedene js-Dateien, eine für die Klickbehandlung, eine für die Hover-Behandlung und eine für die Rückrufe für die beiden anderen. Es wäre hilfreich, die anderen beiden js in das dritte js selbst zu importieren und nur ein <script>Tag zu haben. Dies kann bei der Organisation helfen. Diese Antwort ist einfach nicht das, wonach die Frage gestellt wurde, und ist in diesem Zusammenhang nicht ideal.
Cannicide
Als ich nach einer Lösung für mein Problem gesucht habe, habe ich richtig gesucht. Google ist jedoch der Meinung, dass dies die richtige Seite ist, und bin hier gelandet. Deshalb habe ich hier meine Antwort geschrieben. Sieht so aus, als hätte ich es richtig gemacht, aufgrund von 15 positiven Stimmen oben. Um die Zeit anderer nicht zu verschwenden, habe ich einen klaren Anfang für mein Szenario gemacht - HTML-Code an die erste Stelle gesetzt -, was als hilfreich erscheint, da Sie geantwortet haben und gesagt haben, HTML sei nicht Ihr Szenario. Hoffe das geklärt.
Manohar Reddy Poreddy
Ja - in der Tat sieht es so aus, als hätten einige Leute nach einem etwas anderen Problem gesucht, für das dies eine Lösung ist, und dies gefunden. Obwohl dies nicht unbedingt die Antwort auf diese Frage ist, ist es definitiv die Antwort auf eine andere, ähnliche Frage. Daher ist es in Ordnung, diese Antwort hier zu haben, da sie denjenigen hilft, die nach dieser Antwort gesucht haben. Vielen Dank für diese Antwort, die es klargestellt hat.
Cannicide
16

Wenn Sie Web Worker verwenden und zusätzliche Skripts in den Bereich des Workers aufnehmen möchten, finden Sie die anderen Antworten zum Hinzufügen von Skripten zumhead funktionieren Tag usw. für Sie nicht.

Glücklicherweise haben Web Worker eine eigene importScriptsFunktion, die eine globale Funktion im Bereich des Web Worker ist, die im Browser selbst enthalten ist, da sie Teil der Spezifikation ist .

Alternativ als die zweithöchste Antwort auf Ihre Frage Highlights gestimmt , RequireJS kann auch mit den Skripten behandeln innerhalb eines Web - Worker (wahrscheinlich BerufungimportScripts selbst, aber mit einem paar anderen nützlichen Funktionen).

Turnerj
quelle
16

In der modernen Sprache mit der Prüfung, ob das Skript bereits geladen wurde, wäre es:

function loadJs(url){
  return new Promise( (resolve, reject) => {
    if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
    const script = document.createElement("script")
    script.src = url
    script.onload = resolve
    script.onerror = reject
    document.head.appendChild(script)
  });
}

Verwendung (asynchron / warten):

try { await loadJs("https://.../script.js") } 
catch(error) {console.log(error)}

oder

await loadJs("https://.../script.js").catch(err => {})

Verwendung (Versprechen):

loadJs("https://.../script.js").then(res => {}).catch(err => {})
Dmitry Sheiko
quelle
Nett. Gute Lösung.
Naftali aka Neal
Prägnant und benötigt nur ES5 und vermeidet elegant einen formellen Rückruf. Vielen Dank, Dmitry!
Eureka
Wow, funktioniert im Browser ohne Server. pi.js = einfach var pi = 3.14. Rufen Sie die Funktion loadJS () überloadJs("pi.js").then(function(){ console.log(pi); });
zipzit
14

Die @importSyntax für den CSS-ähnlichen JavaScript-Import ist mit einem Tool wie Mixture über den speziellen .mixDateityp möglich (siehe hier) ). Ich stelle mir vor, dass die Anwendung intern einfach eine der oben genannten Methoden verwendet, obwohl ich es nicht weiß.

Aus der Mixture-Dokumentation zu .mixDateien:

Mix-Dateien sind einfach .js- oder .css-Dateien mit .mix. im Dateinamen. Eine Mix-Datei erweitert einfach die Funktionalität einer normalen Stil- oder Skriptdatei und ermöglicht das Importieren und Kombinieren.

Hier ist eine Beispieldatei .mix, die mehrere .jsDateien zu einer kombiniert :

// scripts-global.mix.js
// Plugins - Global

@import "global-plugins/headroom.js";
@import "global-plugins/retina-1.1.0.js";
@import "global-plugins/isotope.js";
@import "global-plugins/jquery.fitvids.js";

Mixture gibt dies als scripts-global.jsund auch als minimierte Version aus (scripts-global.min.js ).

Hinweis: Ich bin in keiner Weise mit Mixture verbunden, außer dass ich es als Front-End-Entwicklungstool verwende. Ich bin auf diese Frage gestoßen, als ich a.mix JavaScript-Datei in Aktion gesehen habe (in einer der Mixture-Boilerplates) und ein bisschen verwirrt war ("Sie können das tun?", Dachte ich mir). Dann wurde mir klar, dass es sich um einen anwendungsspezifischen Dateityp handelte (etwas enttäuschend, einverstanden). Trotzdem dachte ich, das Wissen könnte für andere hilfreich sein.

UPDATE : Die Mischung ist jetzt kostenlos (offline).

UPDATE : Die Mischung wird jetzt eingestellt. Alte Mischungsfreigaben sind noch verfügbar

Isaac Gregson
quelle
Dies wäre fantastisch, wenn es ein Knotenmodul wäre.
b01
@ b01 Klingt nach einer Herausforderung;) Wenn ich nur die Zeit hätte ... vielleicht tut es jemand anderes?
Isaac Gregson
13

Meine übliche Methode ist:

var require = function (src, cb) {
    cb = cb || function () {};

    var newScriptTag = document.createElement('script'),
        firstScriptTag = document.getElementsByTagName('script')[0];
    newScriptTag.src = src;
    newScriptTag.async = true;
    newScriptTag.onload = newScriptTag.onreadystatechange = function () {
        (!this.readyState || this.readyState === 'loaded' || this.readyState === 'complete') && (cb());
    };
    firstScriptTag.parentNode.insertBefore(newScriptTag, firstScriptTag);
}

Es funktioniert großartig und verwendet für mich kein erneutes Laden von Seiten. Ich habe die AJAX-Methode ausprobiert (eine der anderen Antworten), aber sie scheint für mich nicht so gut zu funktionieren.

Hier ist eine Erklärung, wie der Code für Neugierige funktioniert: Im Wesentlichen wird ein neues Skript-Tag (nach dem ersten) der URL erstellt. Es wird in den asynchronen Modus versetzt, damit der Rest des Codes nicht blockiert wird, sondern ein Rückruf aufgerufen wird, wenn sich der readyState (der Status des zu ladenden Inhalts) in "geladen" ändert.

Christopher Dumas
quelle
13

Obwohl diese Antworten großartig sind, gibt es eine einfache "Lösung", die es seit dem Laden des Skripts gibt und die 99,999% der Anwendungsfälle der meisten Menschen abdeckt. Fügen Sie einfach das benötigte Skript vor dem Skript ein, das es benötigt. Bei den meisten Projekten dauert es nicht lange, um festzustellen, welche Skripte in welcher Reihenfolge benötigt werden.

<!DOCTYPE HTML>
<html>
    <head>
        <script src="script1.js"></script>
        <script src="script2.js"></script>
    </head>
    <body></body>
</html>

Wenn script2 script1 benötigt, ist dies wirklich der absolut einfachste Weg, so etwas zu tun. Ich bin sehr überrascht, dass niemand dies angesprochen hat, da dies die offensichtlichste und einfachste Antwort ist, die in fast jedem Einzelfall zutreffen wird.

KthProg
quelle
1
Ich vermute, für viele Menschen, auch für mich, brauchen wir einen dynamischen Dateinamen.
Stuart McIntyre
1
@StuartMcIntyre Legen Sie in diesem Fall das src-Attribut des Skript-Tags zur Laufzeit fest und warten Sie auf das Onload-Ereignis (in diesem Fall gibt es 2019 natürlich bessere Lösungen).
KthProg
12

Ich habe ein einfaches Modul geschrieben, das das Importieren / Einschließen von Modulskripten in JavaScript automatisiert. Eine ausführliche Erläuterung des Codes finden Sie im Blogbeitrag JavaScript require / import / include modules .

// ----- USAGE -----

require('ivar.util.string');
require('ivar.net.*');
require('ivar/util/array.js');
require('http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js');

ready(function(){
    //Do something when required scripts are loaded
});

    //--------------------

var _rmod = _rmod || {}; //Require module namespace
_rmod.LOADED = false;
_rmod.on_ready_fn_stack = [];
_rmod.libpath = '';
_rmod.imported = {};
_rmod.loading = {
    scripts: {},
    length: 0
};

_rmod.findScriptPath = function(script_name) {
    var script_elems = document.getElementsByTagName('script');
    for (var i = 0; i < script_elems.length; i++) {
        if (script_elems[i].src.endsWith(script_name)) {
            var href = window.location.href;
            href = href.substring(0, href.lastIndexOf('/'));
            var url = script_elems[i].src.substring(0, script_elems[i].length - script_name.length);
            return url.substring(href.length+1, url.length);
        }
    }
    return '';
};

_rmod.libpath = _rmod.findScriptPath('script.js'); //Path of your main script used to mark
                                                   //the root directory of your library, any library.


_rmod.injectScript = function(script_name, uri, callback, prepare) {

    if(!prepare)
        prepare(script_name, uri);

    var script_elem = document.createElement('script');
    script_elem.type = 'text/javascript';
    script_elem.title = script_name;
    script_elem.src = uri;
    script_elem.async = true;
    script_elem.defer = false;

    if(!callback)
        script_elem.onload = function() {
            callback(script_name, uri);
        };
    document.getElementsByTagName('head')[0].appendChild(script_elem);
};

_rmod.requirePrepare = function(script_name, uri) {
    _rmod.loading.scripts[script_name] = uri;
    _rmod.loading.length++;
};

_rmod.requireCallback = function(script_name, uri) {
    _rmod.loading.length--;
    delete _rmod.loading.scripts[script_name];
    _rmod.imported[script_name] = uri;

    if(_rmod.loading.length == 0)
        _rmod.onReady();
};

_rmod.onReady = function() {
    if (!_rmod.LOADED) {
        for (var i = 0; i < _rmod.on_ready_fn_stack.length; i++){
            _rmod.on_ready_fn_stack[i]();
        });
        _rmod.LOADED = true;
    }
};

_.rmod = namespaceToUri = function(script_name, url) {
    var np = script_name.split('.');
    if (np.getLast() === '*') {
        np.pop();
        np.push('_all');
    }

    if(!url)
        url = '';

    script_name = np.join('.');
    return  url + np.join('/')+'.js';
};

//You can rename based on your liking. I chose require, but it
//can be called include or anything else that is easy for you
//to remember or write, except "import", because it is reserved
//for future use.
var require = function(script_name) {
    var uri = '';
    if (script_name.indexOf('/') > -1) {
        uri = script_name;
        var lastSlash = uri.lastIndexOf('/');
        script_name = uri.substring(lastSlash+1, uri.length);
    } 
    else {
        uri = _rmod.namespaceToUri(script_name, ivar._private.libpath);
    }

    if (!_rmod.loading.scripts.hasOwnProperty(script_name)
     && !_rmod.imported.hasOwnProperty(script_name)) {
        _rmod.injectScript(script_name, uri,
            _rmod.requireCallback,
                _rmod.requirePrepare);
    }
};

var ready = function(fn) {
    _rmod.on_ready_fn_stack.push(fn);
};
stamat
quelle
10

Dieses Skript fügt eine JavaScript-Datei oben in jedes andere <script>Tag ein:

(function () {
    var li = document.createElement('script'); 
    li.type = 'text/javascript'; 
    li.src= "http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"; 
    li.async=true; 
    var s = document.getElementsByTagName('script')[0]; 
    s.parentNode.insertBefore(li, s);
})();
Vicky Gonsalves
quelle
10

Es gibt auch Head.js . Es ist sehr einfach zu handhaben:

head.load("js/jquery.min.js",
          "js/jquery.someplugin.js",
          "js/jquery.someplugin.css", function() {
  alert("Everything is ok!");
});

Wie Sie sehen, ist es einfacher als Require.js und so bequem wie die $.getScriptMethode von jQuery . Es hat auch einige erweiterte Funktionen, wie bedingtes Laden, Funktionserkennung und vieles mehr .

Ale
quelle
10

Es gibt viele mögliche Antworten auf diese Frage. Meine Antwort basiert offensichtlich auf einer Reihe von ihnen. Dies ist, was ich am Ende hatte, nachdem ich alle Antworten durchgelesen hatte.

Das Problem mit $.getScriptund wirklich jeder anderen Lösung, die nach Abschluss des Ladevorgangs einen Rückruf erfordert, besteht darin, dass Sie nicht mehr wissen können, wann alle Skripte geladen wurden (sobald sie verschachtelt sind, wenn Sie mehrere Dateien haben, die sie verwenden und voneinander abhängig sind) in mehreren Dateien).

Beispiel:

file3.js

var f3obj = "file3";

// Define other stuff

file2.js:

var f2obj = "file2";
$.getScript("file3.js", function(){

    alert(f3obj);

    // Use anything defined in file3.
});

file1.js:

$.getScript("file2.js", function(){
    alert(f3obj); //This will probably fail because file3 is only guaranteed to have loaded inside the callback in file2.
    alert(f2obj);

    // Use anything defined in the loaded script...
});

Sie haben Recht, wenn Sie sagen, Sie könnten Ajax für die synchrone Ausführung angeben oder XMLHttpRequest verwenden Der aktuelle Trend scheint jedoch darin zu bestehen, synchrone Anforderungen zu verwerfen, sodass Sie möglicherweise jetzt oder in Zukunft keine vollständige Browserunterstützung erhalten.

Sie könnten versuchen, $.whenein Array von zurückgestellten Objekten zu überprüfen, aber jetzt tun Sie dies in jeder Datei und Datei2 wird als geladen betrachtet, sobald die $.whenAusführung nicht ausgeführt wird, wenn der Rückruf ausgeführt wird. Daher setzt Datei1 die Ausführung fort, bevor Datei3 geladen wird . Das hat wirklich immer noch das gleiche Problem.

Ich beschloss, rückwärts statt vorwärts zu gehen. Danke document.writeln. Ich weiß, dass es tabu ist, aber solange es richtig verwendet wird, funktioniert es gut. Am Ende erhalten Sie Code, der einfach zu debuggen ist, im DOM korrekt angezeigt wird und die Reihenfolge sicherstellen kann, in der die Abhängigkeiten korrekt geladen werden.

Sie können natürlich $ ("body"). Append () verwenden, aber dann können Sie nicht mehr richtig debuggen.

HINWEIS: Sie dürfen dies nur verwenden, während die Seite geladen wird, da sonst ein leerer Bildschirm angezeigt wird. Mit anderen Worten, platzieren Sie dies immer vor / außerhalb von document.ready . Ich habe dies nicht getestet, nachdem die Seite in einem Klickereignis oder ähnlichem geladen wurde, aber ich bin mir ziemlich sicher, dass es fehlschlagen wird.

Ich mochte die Idee, jQuery zu erweitern, aber das müssen Sie natürlich nicht.

Vor dem Aufruf document.writelnwird überprüft, ob das Skript noch nicht geladen wurde, indem alle Skriptelemente ausgewertet werden.

Ich gehe davon aus, dass ein Skript erst dann vollständig ausgeführt wird, wenn sein document.readyEreignis ausgeführt wurde. (Ich weiß, dass die Verwendung document.readynicht erforderlich ist, aber viele Leute verwenden sie, und die Handhabung ist ein Schutz.)

Wenn die zusätzlichen Dateien geladen werden, werden die document.readyRückrufe in der falschen Reihenfolge ausgeführt. Um dies zu beheben, wenn ein Skript tatsächlich geladen wird, wird das Skript, das es importiert hat, selbst erneut importiert und die Ausführung angehalten. Dies führt dazu, dass der document.readyRückruf der Ursprungsdatei jetzt nach einem beliebigen Skript ausgeführt wird, das sie importiert.

Anstelle dieses Ansatzes könnten Sie versuchen, die jQuery zu ändern readyList, aber dies schien eine schlechtere Lösung zu sein.

Lösung:

$.extend(true,
{
    import_js : function(scriptpath, reAddLast)
    {
        if (typeof reAddLast === "undefined" || reAddLast === null)
        {
            reAddLast = true; // Default this value to true. It is not used by the end user, only to facilitate recursion correctly.
        }

        var found = false;
        if (reAddLast == true) // If we are re-adding the originating script we do not care if it has already been added.
        {
            found = $('script').filter(function () {
                return ($(this).attr('src') == scriptpath);
            }).length != 0; // jQuery to check if the script already exists. (replace it with straight JavaScript if you don't like jQuery.
        }

        if (found == false) {

            var callingScriptPath = $('script').last().attr("src"); // Get the script that is currently loading. Again this creates a limitation where this should not be used in a button, and only before document.ready.

            document.writeln("<script type='text/javascript' src='" + scriptpath + "'></script>"); // Add the script to the document using writeln

            if (reAddLast)
            {
                $.import_js(callingScriptPath, false); // Call itself with the originating script to fix the order.
                throw 'Readding script to correct order: ' + scriptpath + ' < ' + callingScriptPath; // This halts execution of the originating script since it is getting reloaded. If you put a try / catch around the call to $.import_js you results will vary.
            }
            return true;
        }
        return false;
    }
});

Verwendungszweck:

Datei3:

var f3obj = "file3";

// Define other stuff
$(function(){
    f3obj = "file3docready";
});

Datei2:

$.import_js('js/file3.js');
var f2obj = "file2";
$(function(){
    f2obj = "file2docready";
});

Datei1:

$.import_js('js/file2.js');

// Use objects from file2 or file3
alert(f3obj); // "file3"
alert(f2obj); // "file2"

$(function(){
    // Use objects from file2 or file3 some more.
    alert(f3obj); //"file3docready"
    alert(f2obj); //"file2docready"
});
lockiges Haargenie
quelle
Genau das heißt es in der aktuell akzeptierten Antwort: einfach nicht genug.
Cannicide
Der Hauptunterschied besteht darin, dass bei fehlender Abhängigkeit das Skript-Tag für die Abhängigkeit hinzugefügt wird, dann auch das Skript-Tag für die aufrufende Datei hinzugefügt wird und ein Fehler ausgegeben wird, der die Ausführung anhält. Dadurch werden die Skripte in der richtigen Reihenfolge verarbeitet und ausgeführt, und Rückrufe sind nicht mehr erforderlich. Das abhängige Skript wird also vor dem aufrufenden Skript geladen und ausgeführt, während die Verschachtelung unterstützt wird.
Curlyhairedgenius
"Der aktuelle Trend scheint darin zu bestehen, synchrone Anforderungen abzulehnen". Dies gilt nur, weil viele Entwickler sie missbraucht und Benutzer unnötig warten lassen. Wenn die Anforderung jedoch wie eine Include-Anweisung von Natur aus synchron ist, ist einfaches synchrones Ajax in Ordnung. Ich habe eine allgemeine JavaScript-Erweiterungsfunktion erstellt, die Funktionen wie das Lesen einer Datei, die nicht Teil von JavaScript ist, synchron ausführt, indem eine PHP- "Server" -Datei ausgeführt wird, und finde sie sehr nützlich, wenn ich Apps mit JavaScript schreibe. Für einen solchen Ajax wird kein lokaler Webserver benötigt.
David Spector
10

Es gibt verschiedene Möglichkeiten, Module in Javascript zu implementieren. Hier sind die 2 beliebtesten:

ES6-Module

Browser unterstützen dieses Modulationssystem noch nicht. Damit Sie diese Syntax verwenden können, müssen Sie einen Bundler wie das Webpack verwenden. Die Verwendung eines Bundlers ist ohnehin besser, da dadurch alle Ihre verschiedenen Dateien zu einer einzigen (oder paarbezogenen) Datei kombiniert werden können. Dadurch werden die Dateien vom Server schneller an den Client gesendet, da mit jeder HTTP-Anforderung ein gewisser Overhead verbunden ist. Durch Reduzieren der gesamten HTTP-Anforderung verbessern wir somit die Leistung. Hier ist ein Beispiel für ES6-Module:

// main.js file

export function add (a, b) {
  return a + b;
}

export default function multiply (a, b) {
  return a * b;
}


// test.js file

import {add}, multiply from './main';   // for named exports between curly braces {export1, export2}
                                        // for default exports without {}

console.log(multiply(2, 2));  // logs 4

console.log(add(1, 2));  // logs 3

CommonJS (verwendet in NodeJS)

Dieses Modulationssystem wird in NodeJS verwendet. Grundsätzlich fügen Sie Ihre Exporte einem Objekt hinzu, das aufgerufen wird module.exports. Sie können dann über a auf dieses Objekt zugreifen require('modulePath'). Hierbei ist es wichtig zu wissen, dass diese Module zwischengespeichert werden. Wenn Sie also require()ein bestimmtes Modul zweimal verwenden, wird das bereits erstellte Modul zurückgegeben.

// main.js file

function add (a, b) {
  return a + b;
}

module.exports = add;  // here we add our add function to the exports object


// test.js file

const add = require('./main'); 

console.log(add(1,2));  // logs 3
Willem van der Veen
quelle
9

Ich bin auf diese Frage gekommen, weil ich nach einer einfachen Möglichkeit gesucht habe, eine Sammlung nützlicher JavaScript-Plugins zu verwalten. Nachdem ich einige der Lösungen hier gesehen hatte, kam ich auf Folgendes:

  1. Richten Sie eine Datei mit dem Namen "plugins.js" ein (oder extensions.js oder was auch immer Sie wollen). Halten Sie Ihre Plugin-Dateien zusammen mit dieser einen Master-Datei.

  2. plugins.js hat ein Array namens pluginNames[], über das wir iterieren each()und dann <script>für jedes Plugin ein Tag an den Kopf anhängen

//set array to be updated when we add or remove plugin files
var pluginNames = ["lettering", "fittext", "butterjam", etc.];

//one script tag for each plugin
$.each(pluginNames, function(){
    $('head').append('<script src="js/plugins/' + this + '.js"></script>');
});
  1. Rufen Sie manuell nur die eine Datei in Ihrem Kopf auf:
    <script src="js/plugins/plugins.js"></script>

ABER:

Obwohl alle Plugins wie vorgesehen in das Head-Tag eingefügt werden, werden sie nicht immer vom Browser ausgeführt, wenn Sie auf die Seite klicken oder sie aktualisieren.

Ich habe festgestellt, dass es zuverlässiger ist, nur die Skript-Tags in ein PHP-Include zu schreiben. Sie müssen es nur einmal schreiben und das ist genauso viel Arbeit wie das Aufrufen des Plugins mit JavaScript.

rgb_life
quelle
@will, Ihre Lösung sieht viel sauberer aus als meine und ich befürchte, dass ich einige Fehler haben könnte, wenn ich meine verwende, da sie .append () verwendet. Um dies zu verwenden, können Sie diese Funktion nur einmal für jede Plugin-Datei aufrufen, die Sie einschließen möchten.
rgb_life