Gibt es in JavaScript etwas Ähnliches wie @import
in CSS, mit dem Sie eine JavaScript-Datei in eine andere JavaScript-Datei einfügen können?
script
Tags verwenden?
Gibt es in JavaScript etwas Ähnliches wie @import
in CSS, mit dem Sie eine JavaScript-Datei in eine andere JavaScript-Datei einfügen können?
script
Tags verwenden?
Antworten:
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.
ECMAScript (ES6) -Module werden in Node.js seit Version 8.5 mit dem --experimental-modules
Flag 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.json
oder die Dateien die Erweiterung geben .mjs
. (Ebenso können Module, die mit dem vorherigen CJS-Modul von Node.js geschrieben wurden, benannt werden, .cjs
wenn 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 .mjs
Sie module.mjs
:
export function hello() {
return "Hello";
}
Dann main.mjs
:
import { hello } from './module.mjs';
let val = hello(); // val is "Hello";
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 .mjs
Erweiterung 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/
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
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.
Sie können ein zusätzliches Skript mit einem AJAX-Aufruf laden und dann eval
zum 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.
Wie bei Dynamic Imports können Sie ein oder mehrere Skripte mit einem fetch
Aufruf 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)}`)
})
Die jQuery- Bibliothek bietet Ladefunktionen in einer Zeile :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded but not necessarily executed.");
});
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 .
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.js
enthä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.
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
onreadystatechange
Ereignis und die readyState
Eigenschaft). 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
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.
...
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.js
Datei im Haupt-HTML und dann das Skript, main.js
mit $.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.js
wird die hello()
Funktion aufgerufen und Sie erhalten die Warnung.
(Diese Antwort ist eine Antwort auf den Kommentar von e-satis).
jQuery.getScript
, auf diese Weise müssen Sie sich nicht um das Schreiben des Plugins kümmern ...
script
Elements an head
dazu, dass es asynchron ausgeführt wird, es sei denn, das async
ist speziell auf eingestellt false
.
"
, wird der Code
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();
async: false
angeblich veraltet ist, nicht zu stützen. Es ist nicht! Wie in Ihrem Zitat angegeben, handelt es sich nur um jqXHR-bezogene Inhalte.
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 cond
aus 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:
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");
js.onload = callback;
Anweisung import
ist 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;
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)
}
script.onload = callback;
var
, wird die Variable global sein?
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-origin
in seiner Antwort einen Header festlegen muss, damit diese domänenübergreifend funktioniert .
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
<script>
Tag laden , nicht über XMLHttpRequest
.
const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
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 .
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 script
Element anstelle von head
oder suchen, body
ist, dass einige Browser kein Element erstellen, wenn es fehlt, aber wir haben garantiert ein script
Element - dieses. Lesen Sie mehr unter http://www.jspatterns.com/the-ridiculous-case-of-adding-a-script-element/ .
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 $.getScript
Methode verwenden.
$.getScript("another_script.js");
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
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.js
und 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(){}
}
};
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:
A = {};
A.func1 = function() {
console.log("func1");
}
A.func2 = function() {
console.log("func2");
}
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>
Dies sollte tun:
xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
eval
ist, was daran falsch ist. Aus Crockford : " Ist eval
böse. Die eval
Funktion ist die am häufigsten missbrauchte Funktion von JavaScript. Vermeiden Sie sie. eval
Hat Aliase. Verwenden Sie den Function
Konstruktor nicht . Übergeben Sie keine Zeichenfolgen an setTimeout
oder setInterval
." Wenn Sie sein "JavaScript: The Good Parts" nicht gelesen haben, gehen Sie jetzt raus und machen Sie es. Sie werden es nicht bereuen.
http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStuff/userjs/aagmfunctions.js
)
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:
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.
import
. Sie benötigen eine HTML-Datei, um Inhalte von einer JS-Datei in eine andere zu übertragen.
<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.
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 importScripts
Funktion, 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).
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 => {})
var pi = 3.14
. Rufen Sie die Funktion loadJS () überloadJs("pi.js").then(function(){ console.log(pi); });
Die @import
Syntax für den CSS-ähnlichen JavaScript-Import ist mit einem Tool wie Mixture über den speziellen .mix
Dateityp 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 .mix
Dateien:
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 .js
Dateien 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.js
und 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
var js = document.createElement("script");
js.type = "text/javascript";
js.src = jsFilePath;
document.body.appendChild(js);
body
noch nicht vorhanden ist oder nicht geändert werden kann. Es hilft auch, Antworten zu erklären.
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.
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.
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);
};
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);
})();
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 $.getScript
Methode von jQuery . Es hat auch einige erweiterte Funktionen, wie bedingtes Laden, Funktionserkennung und vieles mehr .
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 $.getScript
und 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).
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, $.when
ein Array von zurückgestellten Objekten zu überprüfen, aber jetzt tun Sie dies in jeder Datei und Datei2 wird als geladen betrachtet, sobald die $.when
Ausfü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.writeln
wird ü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.ready
Ereignis ausgeführt wurde. (Ich weiß, dass die Verwendung document.ready
nicht erforderlich ist, aber viele Leute verwenden sie, und die Handhabung ist ein Schutz.)
Wenn die zusätzlichen Dateien geladen werden, werden die document.ready
Rü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.ready
Rü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"
});
Es gibt verschiedene Möglichkeiten, Module in Javascript zu implementieren. Hier sind die 2 beliebtesten:
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
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
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:
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.
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>');
});
<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.