Hoe kunt u een JavaScript-bestand betrouwbaar en dynamisch laden? Dit kan worden gebruikt om een module of component te implementeren die, wanneer ‘geïnitialiseerd’, de component dynamisch alle benodigde JavaScript-bibliotheekscripts op aanvraag laadt.
De client die de component gebruikt, hoeft niet alle bibliotheekscriptbestanden te laden (en handmatig <script>
-tags in hun webpagina in te voegen) die deze component implementeren – alleen de ‘hoofd ‘ component scriptbestand.
Hoe doen reguliere JavaScript-bibliotheken dit (prototype, jQuery, enz.)?Voegen deze tools meerdere JavaScript-bestanden samen tot één herdistribueerbare ‘build’-versie van een scriptbestand? Of doen ze dynamisch laden van ondersteunende ‘bibliotheek’-scripts?
Een aanvulling op deze vraag: is er een manier om de gebeurtenis af te handelen nadat een dynamisch opgenomen JavaScript-bestand is geladen?Prototype heeft document.observe
voor documentbrede gebeurtenissen . Voorbeeld:
document.observe("dom:loaded", function() {
// initially hide all containers for tab content
$$('div.tabcontent').invoke('hide');
});
Wat zijn de beschikbare gebeurtenissen voor een scriptelement?
Antwoord 1, autoriteit 100%
U kunt dynamisch een scriptelement maken met behulp van Prototypes:
new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});
Het probleem hier is dat we niet weten wanneerhet externe scriptbestand volledig is geladen.
We willen onze afhankelijke code vaak op de volgende regel en schrijven graag iets als:
if (iNeedSomeMore) {
Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
myFancyMethod(); // cool, no need for callbacks!
}
Er is een slimme manier om scriptafhankelijkheden te injecteren zonder callbacks. Je hoeft alleen maar het script op te halen via een synchroon AJAX-verzoeken het script op globaal niveau te evalueren.
Als u Prototype gebruikt, ziet de Script.load-methode er als volgt uit:
var Script = {
_loadedScripts: [],
include: function(script) {
// include script only once
if (this._loadedScripts.include(script)) {
return false;
}
// request file synchronous
var code = new Ajax.Request(script, {
asynchronous: false,
method: "GET",
evalJS: false,
evalJSON: false
}).transport.responseText;
// eval code on global level
if (Prototype.Browser.IE) {
window.execScript(code);
} else if (Prototype.Browser.WebKit) {
$$("head").first().insert(Object.extend(
new Element("script", {
type: "text/javascript"
}), {
text: code
}
));
} else {
window.eval(code);
}
// remember included script
this._loadedScripts.push(script);
}
};
Antwoord 2, autoriteit 97%
Er is geen import / include / required in javascript, maar er zijn twee manieren om te bereiken wat je wilt:
1 – U kunt het laden met een AJAX-oproep en vervolgens eval gebruiken.
Dit is de meest eenvoudige manier, maar het is beperkt tot uw domein vanwege de veiligheidsinstellingen van Javascript, en het gebruik van eval opent de deur naar bugs en hacks.
2 – Voeg een scriptelement toe met de script-URL in de HTML.
Absoluut de beste manier om te gaan. Je kunt het script zelfs vanaf een buitenlandse server laden, en het is schoon omdat je de browserparser gebruikt om de code te evalueren. Je kunt het script
element in het head
element van de webpagina plaatsen, of onderaan de body
.
Beide oplossingen worden hier besproken en geïllustreerd.
Er is een groot probleem dat u moet weten. Als u dat doet, betekent dit dat u de code op afstand laadt. Moderne webbrowsers laden het bestand en blijven uw huidige script uitvoeren omdat ze alles asynchroon laden om de prestaties te verbeteren.
Het betekent dat als je deze trucs direct toepast, je de nieuw geladen code niet kunt gebruiken op de volgende regel nadat je hem hebt gevraagd te laden, omdat deze nog steeds aan het laden is.
Bijvoorbeeld: my_lovely_script.js bevat 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
Vervolgens herlaad je de pagina door op F5 te drukken. En het werkt! Verwarrend…
Dus wat eraan te doen?
Nou, je kunt de hack gebruiken die de auteur voorstelt in de link die ik je gaf. Samengevat, voor mensen met haast gebruikt hij en event om een callback-functie uit te voeren wanneer het script is geladen. U kunt dus alle code met behulp van de externe bibliotheek in de terugbelfunctie plaatsen. BIJV.:
function loadScript(url, callback)
{
// adding the script element to the head as suggested before
var head = document.getElementsByTagName('head')[0];
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);
}
Vervolgens schrijf je de code die je wilt gebruiken NADAT het script is geladen in een lambda-functie :
var myPrettyCode = function() {
// here, do what ever you want
};
Dan voer je dat allemaal uit:
loadScript("my_lovely_script.js", myPrettyCode);
Ok, ik snap het. Maar het is vervelend om al deze dingen te schrijven.
In dat geval kun je zoals altijd het fantastische gratis jQuery-framework gebruiken, waarmee je precies hetzelfde kunt doen in één regel :
$.getScript("my_lovely_script.js", function() {
alert("Script loaded and executed.");
// here you can use anything you defined in the loaded script
});
Antwoord 3, autoriteit 35%
Ik heb onlangs een veel minder gecompliceerde versiegebruikt met jQuery:
<script src="scripts/jquery.js"></script>
<script>
var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
var $head = $("head");
for (var i = 0; i < js.length; i++) {
$head.append("<script src=\"" + js[i] + "\"></scr" + "ipt>");
}
</script>
Het werkte prima in elke browser waarin ik het heb getest: IE6/7, Firefox, Safari, Opera.
Update:jQuery-loze versie:
<script>
var js = ["scripts/jquery.dimensions.js", "scripts/shadedborder.js", "scripts/jqmodal.js", "scripts/main.js"];
for (var i = 0, l = js.length; i < l; i++) {
document.getElementsByTagName("head")[0].innerHTML += ("<script src=\"" + js[i] + "\"></scr" + "ipt>");
}
</script>
Antwoord 4, autoriteit 23%
Ik deed in principe hetzelfde als Adam, maar met een kleine wijziging om ervoor te zorgen dat ik het element head
aan het toevoegen was om de klus te klaren. Ik heb eenvoudig een functie include
gemaakt (code hieronder) om zowel script- als CSS-bestanden te verwerken.
Deze functie controleert ook of het script of CSS-bestand niet al dynamisch is geladen. Er wordt niet gecontroleerd op met de hand gecodeerde waarden en er was misschien een betere manier om dat te doen, maar het heeft zijn doel gediend.
function include( url, type ){
// First make sure it hasn't been loaded by something else.
if( Array.contains( includedFile, url ) )
return;
// Determine the MIME type.
var jsExpr = new RegExp( "js$", "i" );
var cssExpr = new RegExp( "css$", "i" );
if( type == null )
if( jsExpr.test( url ) )
type = 'text/javascript';
else if( cssExpr.test( url ) )
type = 'text/css';
// Create the appropriate element.
var element = null;
switch( type ){
case 'text/javascript' :
element = document.createElement( 'script' );
element.type = type;
element.src = url;
break;
case 'text/css' :
element = document.createElement( 'link' );
element.rel = 'stylesheet';
element.type = type;
element.href = url;
break;
}
// Insert it to the <head> and the array to ensure it is not
// loaded again.
document.getElementsByTagName("head")[0].appendChild( element );
Array.add( includedFile, url );
}
Antwoord 5, autoriteit 16%
nog een geweldig antwoord
$.getScript("my_lovely_script.js", function(){
alert("Script loaded and executed.");
// here you can use anything you defined in the loaded script
});
https://stackoverflow.com/a/950146/671046
Antwoord 6, autoriteit 10%
Hier is een voorbeeldcode die ik heb gevonden… heeft iemand een betere manier?
function include(url)
{
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
var nodes = document.getElementsByTagName("*");
var node = nodes[nodes.length -1].parentNode;
node.appendChild(s);
}
Antwoord 7, autoriteit 7%
Als je jQuery al hebt geladen, moet je $.getScriptgebruiken.
Dit heeft een voordeel ten opzichte van de andere antwoorden hier, omdat je een ingebouwde callback-functie hebt (om te garanderen dat het script wordt geladen voordat de afhankelijke code wordt uitgevoerd) en je caching kunt regelen.
Antwoord 8, autoriteit 6%
Dynamische moduleimport geland in Firefox 67+.
(async () => {
await import('./synth/BubbleSynth.js')
})()
Met foutafhandeling:
(async () => {
await import('./synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()
Het werkt ook voor alle soorten bibliotheken die geen module zijn, in dit geval is de lib op de oude manier beschikbaar op het window-object, maar alleen op aanvraag, wat prettig is.
Voorbeeld met suncalc.js, de server moet CORS ingeschakeldom op deze manier te werken!
(async () => {
await import('https://cdnjs.cloudflare.com/ajax/libs/suncalc/1.8.0/suncalc.min.js')
.then(function(){
let times = SunCalc.getTimes(new Date(), 51.5,-0.1);
console.log("Golden Hour today in London: " + times.goldenHour.getHours() + ':' + times.goldenHour.getMinutes() + ". Take your pics!")
})
})()
Antwoord 9, autoriteit 5%
Als u een SYNC-script wilt laden, moet u de scripttekst rechtstreeks aan het HTML HEAD-element toevoegen. Door het toe te voegen zoals wordt een ASYNC-belasting geactiveerd. Gebruik XHR om scripttekst uit een extern bestand synchroon te laden. Hieronder een kort voorbeeld (het gebruikt delen van andere antwoorden in deze en andere berichten):
/*sample requires an additional method for array prototype:*/
if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) { if (this[i] === obj) return true; }
return false;
};
};
/*define object that will wrap our logic*/
var ScriptLoader = {
LoadedFiles: [],
LoadFile: function (url) {
var self = this;
if (this.LoadedFiles.contains(url)) return;
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
self.LoadedFiles.push(url);
self.AddScript(xhr.responseText);
} else {
if (console) console.error(xhr.statusText);
}
}
};
xhr.open("GET", url, false);/*last parameter defines if call is async or not*/
xhr.send(null);
},
AddScript: function (code) {
var oNew = document.createElement("script");
oNew.type = "text/javascript";
oNew.textContent = code;
document.getElementsByTagName("head")[0].appendChild(oNew);
}
};
/*Load script file. ScriptLoader will check if you try to load a file that has already been loaded (this check might be better, but I'm lazy).*/
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
ScriptLoader.LoadFile("Scripts/jquery-2.0.1.min.js");
/*this will be executed right after upper lines. It requires jquery to execute. It requires a HTML input with id "tb1"*/
$(function () { alert($('#tb1').val()); });
Antwoord 10, autoriteit 3%
heeft iemand een betere manier?
Ik denk dat het eenvoudiger zou zijn om het script aan de body toe te voegen dan aan het laatste knooppunt op de pagina. Wat dacht je hiervan:
function include(url) {
var s = document.createElement("script");
s.setAttribute("type", "text/javascript");
s.setAttribute("src", url);
document.body.appendChild(s);
}
Antwoord 11, autoriteit 3%
ik heb nog een andere oplossing gebruikt die ik op het net heb gevonden … deze staat onder creativecommons en het controleert of de bron is opgenomen voordat de functie wordt aangeroepen…
je kunt het bestand hier vinden: include.js
/** include - including .js files from JS - [email protected] - 2005-02-09
** Code licensed under Creative Commons Attribution-ShareAlike License
** http://creativecommons.org/licenses/by-sa/2.0/
**/
var hIncludes = null;
function include(sURI)
{
if (document.getElementsByTagName)
{
if (!hIncludes)
{
hIncludes = {};
var cScripts = document.getElementsByTagName("script");
for (var i=0,len=cScripts.length; i < len; i++)
if (cScripts[i].src) hIncludes[cScripts[i].src] = true;
}
if (!hIncludes[sURI])
{
var oNew = document.createElement("script");
oNew.type = "text/javascript";
oNew.src = sURI;
hIncludes[sURI]=true;
document.getElementsByTagName("head")[0].appendChild(oNew);
}
}
}
Antwoord 12, autoriteit 3%
Ik heb net een geweldige functie ontdekt in YUI 3(op het moment van schrijven beschikbaar in preview-versie). U kunt eenvoudig afhankelijkheden invoegen in YUI-bibliotheken en “externe” modules (wat u zoekt) zonder al te veel code: YUI-lader.
Het beantwoordt ook je tweede vraag over de functie die wordt aangeroepen zodra de externe module is geladen.
Voorbeeld:
YUI({
modules: {
'simple': {
fullpath: "http://example.com/public/js/simple.js"
},
'complicated': {
fullpath: "http://example.com/public/js/complicated.js"
requires: ['simple'] // <-- dependency to 'simple' module
}
},
timeout: 10000
}).use('complicated', function(Y, result) {
// called as soon as 'complicated' is loaded
if (!result.success) {
// loading failed, or timeout
handleError(result.msg);
} else {
// call a function that needs 'complicated'
doSomethingComplicated(...);
}
});
Werkte perfect voor mij en heeft het voordeel van het beheren van afhankelijkheden. Raadpleeg de YUI-documentatie voor een voorbeeld met YUI 2-kalender .
Antwoord 13, autoriteit 3%
Ik weet dat mijn antwoord een beetje laat is voor deze vraag, maar hier is een geweldig artikel in www.html5rocks.com– Diepe duik in de duistere wateren van het laden van scripts.
In dat artikel wordt geconcludeerd dat met betrekking tot browserondersteuning, de beste manier om het JavaScript-bestand dynamisch te laden zonder de weergave van inhoud te blokkeren de volgende manier is:
Aangezien je vier scripts hebt met de namen script1.js, script2.js, script3.js, script4.js
, kun je dit doen door async = false toe te passen:
[
'script1.js',
'script2.js',
'script3.js',
'script4.js'
].forEach(function(src) {
var script = document.createElement('script');
script.src = src;
script.async = false;
document.head.appendChild(script);
});
Nu zegt Spec: samen downloaden, in volgorde uitvoeren zodra alles is gedownload.
Firefox < 3.6, zegt Opera:ik heb geen idee wat dit “asynchrone” ding is, maar het toeval wil dat ik scripts die via JS zijn toegevoegd, uitvoer in de volgorde waarin ze zijn toegevoegd.
Safari 5.0 zegt:ik begrijp “async”, maar ik begrijp niet dat ik het met JS op “false” moet zetten. Ik zal je scripts uitvoeren zodra ze binnenkomen, in welke volgorde dan ook.
IE < 10 zegt:Geen idee over “async”, maar er is een oplossing met “onreadystatechange”.
Al het andere zegt:ik ben je vriend, we gaan dit volgens het boekje doen.
Nu, de volledige code met IE < 10 tijdelijke oplossing:
var scripts = [
'script1.js',
'script2.js',
'script3.js',
'script4.js'
];
var src;
var script;
var pendingScripts = [];
var firstScript = document.scripts[0];
// Watch scripts load in IE
function stateChange() {
// Execute as many scripts in order as we can
var pendingScript;
while (pendingScripts[0] && pendingScripts[0].readyState == 'loaded') {
pendingScript = pendingScripts.shift();
// avoid future loading events from this script (eg, if src changes)
pendingScript.onreadystatechange = null;
// can't just appendChild, old IE bug if element isn't closed
firstScript.parentNode.insertBefore(pendingScript, firstScript);
}
}
// loop through our script urls
while (src = scripts.shift()) {
if ('async' in firstScript) { // modern browsers
script = document.createElement('script');
script.async = false;
script.src = src;
document.head.appendChild(script);
}
else if (firstScript.readyState) { // IE<10
// create a script and add it to our todo pile
script = document.createElement('script');
pendingScripts.push(script);
// listen for state changes
script.onreadystatechange = stateChange;
// must set src AFTER adding onreadystatechange listener
// else we’ll miss the loaded event for cached scripts
script.src = src;
}
else { // fall back to defer
document.write('<script src="' + src + '" defer></'+'script>');
}
}
Een paar trucjes en verkleining later is het 362 bytes
!function(e,t,r){function n(){for(;d[0]&&"loaded"==d[0][f];)c=d.shift(),c[o]=!i.parentNode.insertBefore(c,i)}for(var s,a,c,d=[],i=e.scripts[0],o="onreadystatechange",f="readyState";s=r.shift();)a=e.createElement(t),"async"in i?(a.async=!1,e.head.appendChild(a)):i[f]?(d.push(a),a[o]=n):e.write("<"+t+' src="'+s+'" defer></'+t+">"),a.src=s}(document,"script",[
"//other-domain.com/1.js",
"2.js"
])
Antwoord 14, autoriteit 3%
Er is een nieuwe voorgestelde ECMA-standaard genaamd dynamische import, onlangs opgenomen in Chrome en Safari.
const moduleSpecifier = './dir/someModule.js';
import(moduleSpecifier)
.then(someModule => someModule.foo()); // executes foo method in someModule
Antwoord 15, autoriteit 2%
De techniek die we op het werk gebruiken, is om het javascript-bestand op te vragen met behulp van een AJAX-verzoek en vervolgens te eval() de terugkeer. Als je de prototypebibliotheek gebruikt, ondersteunen ze deze functionaliteit in hun Ajax.Request-oproep.
Antwoord 16, autoriteit 2%
jQuery heeft dit voor mij opgelost met de functie .append()
– gebruikte dit om het volledige jQuery ui-pakket te laden
/*
* FILENAME : project.library.js
* USAGE : loads any javascript library
*/
var dirPath = "../js/";
var library = ["functions.js","swfobject.js","jquery.jeditable.mini.js","jquery-ui-1.8.8.custom.min.js","ui/jquery.ui.core.min.js","ui/jquery.ui.widget.min.js","ui/jquery.ui.position.min.js","ui/jquery.ui.button.min.js","ui/jquery.ui.mouse.min.js","ui/jquery.ui.dialog.min.js","ui/jquery.effects.core.min.js","ui/jquery.effects.blind.min.js","ui/jquery.effects.fade.min.js","ui/jquery.effects.slide.min.js","ui/jquery.effects.transfer.min.js"];
for(var script in library){
$('head').append('<script type="text/javascript" src="' + dirPath + library[script] + '"></script>');
}
Te gebruiken– in de kop van je html/php/etc nadat je jquery.js hebt geïmporteerd, zou je dit ene bestand zo opnemen om het in je hele bibliotheek te laden en het toe te voegen aan de hoofd…
<script type="text/javascript" src="project.library.js"></script>
Antwoord 17, autoriteit 2%
Houd het leuk, kort, eenvoudig en onderhoudbaar! :]
// 3rd party plugins / script (don't forget the full path is necessary)
var FULL_PATH = '', s =
[
FULL_PATH + 'plugins/script.js' // Script example
FULL_PATH + 'plugins/jquery.1.2.js', // jQuery Library
FULL_PATH + 'plugins/crypto-js/hmac-sha1.js', // CryptoJS
FULL_PATH + 'plugins/crypto-js/enc-base64-min.js' // CryptoJS
];
function load(url)
{
var ajax = new XMLHttpRequest();
ajax.open('GET', url, false);
ajax.onreadystatechange = function ()
{
var script = ajax.response || ajax.responseText;
if (ajax.readyState === 4)
{
switch(ajax.status)
{
case 200:
eval.apply( window, [script] );
console.log("library loaded: ", url);
break;
default:
console.log("ERROR: library not loaded: ", url);
}
}
};
ajax.send(null);
}
// initialize a single load
load('plugins/script.js');
// initialize a full load of scripts
if (s.length > 0)
{
for (i = 0; i < s.length; i++)
{
load(s[i]);
}
}
Deze code is gewoon een kort functioneel voorbeeld dat mogelijkextra functionaliteit vereist voor volledige ondersteuning op elk (of gegeven) platform.
Antwoord 18, autoriteit 2%
Zoiets…
<script>
$(document).ready(function() {
$('body').append('<script src="https://maps.googleapis.com/maps/api/js?key=KEY&libraries=places&callback=getCurrentPickupLocation" async defer><\/script>');
});
</script>
Antwoord 19
Er zijn scripts die speciaal voor dit doel zijn ontworpen.
yepnope.jsis ingebouwd in Modernizr en lab.jsis een meer geoptimaliseerde (maar minder gebruiksvriendelijke versie.
Ik zou niet aanraden dit te doen via een grote bibliotheek zoals jQuery of prototype – omdat een van de belangrijkste voordelen van een scriptlader de mogelijkheid is om scripts vroeg te laden – je zou niet moeten wachten tot jQuery & al je dom-elementen worden geladen voordat je een controle uitvoert om te zien of je een script dynamisch wilt laden.
Antwoord 20
Ik heb een eenvoudige module geschreven die het importeren/invoegen van modulescripts in JavaScript automatiseert. Probeer het eens en bespaar wat feedback! 🙂 Raadpleeg deze blogpost voor een gedetailleerde uitleg van de code: http://stamat.wordpress.com/2013/04/12/javascript-require-import-include-modules/
var _rmod = _rmod || {}; //require module namespace
_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;
}
};
//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 np = script_name.split('.');
if (np[np.length-1] === '*') {
np.pop();
np.push('_all');
}
script_name = np.join('.');
var uri = _rmod.libpath + np.join('/')+'.js';
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);
};
// ----- USAGE -----
require('ivar.util.array');
require('ivar.util.string');
require('ivar.net.*');
ready(function(){
//do something when required scripts are loaded
});
21
Een absurde one-liner, voor degenen die denken dat het laden van een js-bibliotheek niet meer dan één regel code zou moeten kosten 😛
await new Promise((resolve, reject) => {let js = document.createElement("script"); js.src="mylibrary.js"; js.onload=resolve; js.onerror=reject; document.body.appendChild(js)});
Als het script dat u wilt importeren een module is, kunt u uiteraard de import(...)
functie.
Antwoord 22
Met Promises kun je het zo vereenvoudigen.
Loader-functie:
const loadCDN = src =>
new Promise((resolve, reject) => {
if (document.querySelector(`head > script[src="${src}"]`) !== null) return resolve()
const script = document.createElement("script")
script.src = src
script.async = true
document.head.appendChild(script)
script.onload = resolve
script.onerror = reject
})
Gebruik (async/wacht):
await loadCDN("https://.../script.js")
Gebruik (belofte):
loadCDN("https://.../script.js").then(res => {}).catch(err => {})
OPMERKING: er was een vergelijkbare oplossing, maar deze controleert niet of het script al is geladen en laadt het script niet elke keer. Deze controleert de eigenschap src.
Antwoord 23
Voor degenen onder jullie die van oneliners houden:
import('./myscript.js');
De kans is groot dat u een foutmelding krijgt, zoals:
Toegang tot script op ‘http://…./myscript.js‘ van oorsprong
‘http://127.0.0.1‘ is geblokkeerd door CORS-beleid: Nee
‘Access-Control-Allow-Origin’ header is aanwezig op de gevraagde
bron.
In dat geval kunt u terugvallen op:
fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
Antwoord 24
Hoezeer ik ook hou van hoe handig de JQuery-aanpak is, de JavaScript-aanpak is niet zo ingewikkeld, maar vereist slechts een kleine aanpassing aan wat je al gebruikt…
Hier is hoe ik JS dynamisch laad (alleen wanneer nodig) en wacht tot ze zijn geladen voordat ik het script uitvoer dat ervan afhankelijk is.
JavaScript-aanpak
//Create a script element that will load
let dynamicScript = document.createElement('script');
//Set source to the script we need to load
dynamicScript.src = 'linkToNeededJsFile.js';
//Set onload to callback function that depends on this script or do inline as shown below
dynamicScript.onload = () => {
//Code that depends on the loaded script should be here
};
//append the created script element to body element
document.body.append(dynamicScript);
Er zijn andere manieren om dit met JS te bereiken, maar ik geef hier de voorkeur aan omdat het de basiskennis van JS vereist die elke ontwikkelaar kan relateren.
Niet onderdeel van het antwoord, maar hier is de JQuery-versie die ik prefereer bij projecten die JQuery al bevatten:
$.getScript('linkToNeededJsFile.js', () => {
//Code that depends on the loaded script should be here
});
Meer over de JQuery-optie hier
Antwoord 25
alle grote javascript-bibliotheken zoals jscript, prototype en YUI hebben ondersteuning voor het laden van scriptbestanden. In YUI kunt u bijvoorbeeld na het laden van de kern het volgende doen om het kalenderbesturingselement te laden
var loader = new YAHOO.util.YUILoader({
require: ['calendar'], // what components?
base: '../../build/',//where do they live?
//filter: "DEBUG", //use debug versions (or apply some
//some other filter?
//loadOptional: true, //load all optional dependencies?
//onSuccess is the function that YUI Loader
//should call when all components are successfully loaded.
onSuccess: function() {
//Once the YUI Calendar Control and dependencies are on
//the page, we'll verify that our target container is
//available in the DOM and then instantiate a default
//calendar into it:
YAHOO.util.Event.onAvailable("calendar_container", function() {
var myCal = new YAHOO.widget.Calendar("mycal_id", "calendar_container");
myCal.render();
})
},
// should a failure occur, the onFailure function will be executed
onFailure: function(o) {
alert("error: " + YAHOO.lang.dump(o));
}
});
// Calculate the dependency and insert the required scripts and css resources
// into the document
loader.insert();
Antwoord 26
Ik heb een aantal van de bovenstaande berichten aangepast met een werkend voorbeeld.
Hier kunnen we ook css en js in dezelfde array geven.
$(document).ready(function(){
if (Array.prototype.contains === undefined) {
Array.prototype.contains = function (obj) {
var i = this.length;
while (i--) { if (this[i] === obj) return true; }
return false;
};
};
/* define object that will wrap our logic */
var jsScriptCssLoader = {
jsExpr : new RegExp( "js$", "i" ),
cssExpr : new RegExp( "css$", "i" ),
loadedFiles: [],
loadFile: function (cssJsFileArray) {
var self = this;
// remove duplicates with in array
cssJsFileArray.filter((item,index)=>cssJsFileArray.indexOf(item)==index)
var loadedFileArray = this.loadedFiles;
$.each(cssJsFileArray, function( index, url ) {
// if multiple arrays are loaded the check the uniqueness
if (loadedFileArray.contains(url)) return;
if( self.jsExpr.test( url ) ){
$.get(url, function(data) {
self.addScript(data);
});
}else if( self.cssExpr.test( url ) ){
$.get(url, function(data) {
self.addCss(data);
});
}
self.loadedFiles.push(url);
});
// don't load twice accross different arrays
},
addScript: function (code) {
var oNew = document.createElement("script");
oNew.type = "text/javascript";
oNew.textContent = code;
document.getElementsByTagName("head")[0].appendChild(oNew);
},
addCss: function (code) {
var oNew = document.createElement("style");
oNew.textContent = code;
document.getElementsByTagName("head")[0].appendChild(oNew);
}
};
//jsScriptCssLoader.loadFile(["css/1.css","css/2.css","css/3.css"]);
jsScriptCssLoader.loadFile(["js/common/1.js","js/2.js","js/common/file/fileReader.js"]);
});