Dynamisch een JavaScript-bestand laden

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.observevoor 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 scriptelement in het headelement 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 headaan het toevoegen was om de klus te klaren. Ik heb eenvoudig een functie includegemaakt (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!")
  })
})()

Snippet uitvouwen


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.comDiepe 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"]);
});

Other episodes