Carica dinamicamente un file JavaScript


168

Come è possibile caricare in modo affidabile e dinamico un file JavaScript? Questo può essere usato per implementare un modulo o un componente che quando "inizializzato" il componente caricherà dinamicamente tutti gli script della libreria JavaScript necessari su richiesta.

Il client che utilizza il componente non è tenuto a caricare tutti i file di script della libreria (e inserire manualmente i <script>tag nella loro pagina Web) che implementano questo componente - solo il file di script del componente "principale".

In che modo le librerie JavaScript tradizionali ottengono questo risultato (prototipo, jQuery, ecc.)? Questi strumenti uniscono più file JavaScript in un'unica versione 'build' ridistribuibile di un file di script? Oppure eseguono un caricamento dinamico di script "libreria" ausiliari?

Un'aggiunta a questa domanda: esiste un modo per gestire l'evento dopo il caricamento di un file JavaScript incluso in modo dinamico? Prototype ha document.observeper eventi a livello di documento. Esempio:

document.observe("dom:loaded", function() {
  // initially hide all containers for tab content
  $$('div.tabcontent').invoke('hide');
});

Quali sono gli eventi disponibili per un elemento di script?


Risposte:


84

Puoi scrivere tag di script dinamici (usando Prototype ):

new Element("script", {src: "myBigCodeLibrary.js", type: "text/javascript"});

Il problema qui è che non sappiamo quando il file di script esterno è completamente caricato.

Vogliamo spesso il nostro codice dipendente nella riga successiva e ci piace scrivere qualcosa del tipo:

if (iNeedSomeMore) {
    Script.load("myBigCodeLibrary.js"); // includes code for myFancyMethod();
    myFancyMethod(); // cool, no need for callbacks!
}

Esiste un modo intelligente per iniettare dipendenze di script senza la necessità di richiamate. Devi semplicemente estrarre lo script tramite una richiesta AJAX sincrona e valutare lo script a livello globale.

Se si utilizza Prototype, il metodo Script.load è simile al seguente:

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

Cosa posso fare per farlo funzionare su più domini? (caricamento script da http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570


@Ciastopiekarz: non controllo web.archive.org.
user2284570,

Quindi devi raschiare i dati a cui vuoi accedere utilizzando qualche altro programma e fornirli a te stesso
David Schumann,

cos'è Ajax.Request ??
Bluejayke,

72

Non esiste importazione / inclusione / richiesta in JavaScript, ma ci sono due modi principali per ottenere ciò che desideri:

1 - È possibile caricarlo con una chiamata AJAX, quindi utilizzare eval.

Questo è il modo più semplice ma è limitato al tuo dominio a causa delle impostazioni di sicurezza di Javascript e l'utilizzo di eval sta aprendo la porta a bug e hack.

2 - Aggiungi un tag di script con l'URL dello script in HTML.

Sicuramente il modo migliore per andare. È possibile caricare lo script anche da un server esterno ed è pulito quando si utilizza il parser del browser per valutare il codice. È possibile inserire il tag nella parte superiore della pagina Web o nella parte inferiore del corpo.

Entrambe queste soluzioni sono discusse e illustrate qui.

Ora, c'è un grosso problema che devi conoscere. Ciò implica che si carica in remoto il codice. I browser Web moderni caricheranno il file e continueranno a eseguire lo script corrente perché caricano tutto in modo asincrono per migliorare le prestazioni.

Significa che se usi questi trucchi direttamente, non sarai in grado di usare il tuo codice appena caricato la riga successiva dopo che hai chiesto di caricarlo, perché continuerà a caricarsi.

Ad esempio: my_lovely_script.js contiene 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

Quindi ricarichi la pagina colpendo F5. E funziona! Confondere ...

Quindi cosa fare al riguardo?

Bene, puoi usare l'hack che l'autore suggerisce nel link che ti ho dato. In breve, per le persone che vanno di fretta, usa en event per eseguire una funzione di callback quando viene caricato lo script. Quindi puoi inserire tutto il codice usando la libreria remota nella funzione di callback. PER ESEMPIO :

function loadScript(url, callback)
{
    // adding the script tag 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);
}

Quindi scrivi il codice che vuoi usare DOPO che lo script è caricato in una funzione lambda:

var myPrettyCode = function() {
    // here, do what ever you want
};

Quindi esegui tutto ciò:

loadScript("my_lovely_script.js", myPrettyCode);

Ok ho capito. Ma è un dolore scrivere tutte queste cose.

Bene, in quel caso, puoi usare come sempre il fantastico framework jQuery gratuito, che ti consente di fare la stessa cosa in una riga:

$.getScript("my_lovely_script.js", function() {
    alert("Script loaded and executed.");
    // here you can use anything you defined in the loaded script
});

11
non riesco a credere quanto sia sottovalutata questa risposta. Grazie.
naftalimich,

2
Scommetto che è perché alle persone non piace leggere oltre la prima riga, a meno che non prometta loro che saranno ricchi se "seguono solo questi tre passaggi segreti per il successo".
Costa

Questo funziona Spero che condividere la mia esperienza qui ti faccia risparmiare tempo perché ho trascorso molte ore su questo. Sto usando Angular 6 e il modello applicato (html, css, jquery) Il problema è che il modello ha un file js che si carica dopo che gli elementi html sono stati caricati per allegare gli eventi dei listener. Quel file js era difficile da eseguire dopo il caricamento dell'app angolare. Aggiungendolo al tag degli script angular app (angular.json) li raggrupperai ma non eseguirai quel file js dopo il caricamento. È troppo codice da riscrivere in dattiloscritto, quindi è stato di grande aiuto. Prossimo commento
Metterò

Ho semplicemente usato questo codice come segue: ngAfterViewInit () {debugger; $ .getScript ("/ assets / js / jquery.app.js", function () {alert ("Script caricato ed eseguito."); // qui puoi usare tutto ciò che hai definito nello script caricato}); }
Nour Lababidi,

Per il '$' in I angolare seguito questa: stackoverflow.com/questions/32050645/...
Nour Lababidi

28

Recentemente ho usato una versione molto meno complicata con 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>

Ha funzionato alla grande in tutti i browser in cui l'ho provato: IE6 / 7, Firefox, Safari, Opera.

Aggiornamento: versione senza jQuery:

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

25
È fantastico ... a meno che tu non stia provando a caricare jquery.

1
Sembra che jQuery inserirà il plug-in Require in jQuery Core per una versione futura: plugins.jquery.com/project/require
Adam

1
Un modo ancora migliore di usare jQuery è usare $.getScript. Vedi la mia risposta
Muhd,

1
Modernizr (yepnope.js) o lab.js sono le soluzioni appropriate per questo. l'utilizzo di una libreria di script pesanti (che deve essere caricata per prima) non è la risposta più adatta per dispositivi mobili o molte altre situazioni.
1finiti

2
I browser e i validatori html di @MaulikGangani lo interpreterebbero come token per terminare lo script.
Travis,

20

Ho fatto praticamente la stessa cosa che hai fatto a Adam, ma con una leggera modifica per assicurarmi di aggiungere il tag head per fare il lavoro. Ho semplicemente creato una funzione di inclusione (codice sotto) per gestire sia i file script che i file css.

Questa funzione verifica inoltre che lo script o il file CSS non siano già stati caricati dinamicamente. Non controlla i valori codificati manualmente e potrebbe esserci stato un modo migliore per farlo, ma è servito allo scopo.

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 tag = null;
    switch( type ){
        case 'text/javascript' :
            tag = document.createElement( 'script' );
            tag.type = type;
            tag.src = url;
            break;
        case 'text/css' :
            tag = document.createElement( 'link' );
            tag.rel = 'stylesheet';
            tag.type = type;
            tag.href = url;
            break;
    }

    // Insert it to the <head> and the array to ensure it is not
    // loaded again.
    document.getElementsByTagName("head")[0].appendChild( tag );
    Array.add( includedFile, url );
}

Senza più contesto di quel Pickle, temo di non avere alcun suggerimento. Il codice sopra funziona così com'è, è stato estratto direttamente da un progetto funzionante.
cavallo pallido,

5
@palehorse, Mike e Muhd, hanno ragione, potrebbe funzionare nel tuo progetto, ma questo perché le variabili "includedFile" e "Array" devono essere definite altrove nel tuo progetto, questo codice da solo non funzionerà, potrebbe essere meglio modificarlo in modo che possa funzionare al di fuori del contesto del progetto o almeno aggiungere un commento che spieghi quali sono quelle variabili non definite (tipo ecc.)
user280109

14

un'altra risposta fantastica

$.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


2
Cosa posso fare per farlo funzionare per il dominio incrociato? (caricamento script da http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

9

Ecco qualche esempio di codice che ho trovato ... qualcuno ha un modo migliore?

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

Cosa posso fare per farlo funzionare per il dominio incrociato? (caricamento script da http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

6

Se hai già caricato jQuery, dovresti usare $ .getScript .

Questo ha un vantaggio rispetto alle altre risposte qui in quanto hai una funzione di callback integrata (per garantire che lo script sia caricato prima dell'esecuzione del codice dipendente) e puoi controllare la memorizzazione nella cache.


4

Se si desidera caricare uno script SYNC , è necessario aggiungere il testo dello script direttamente al tag HTML HEAD. Aggiungendolo come si attiverà un carico ASYNC . Per caricare il testo dello script da file esterno in modo sincrono, utilizzare XHR. Di seguito un breve esempio (utilizza parti di altre risposte in questo e in altri post):

/*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()); });

3

qualcuno ha un modo migliore?

Penso che aggiungere semplicemente lo script al corpo sarebbe più semplice che aggiungerlo all'ultimo nodo della pagina. Cosa ne pensi di questo:

function include(url) {
  var s = document.createElement("script");
  s.setAttribute("type", "text/javascript");
  s.setAttribute("src", url);
  document.body.appendChild(s);
}

Cosa posso fare per farlo funzionare per il dominio incrociato? (caricamento script da http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

ho usato ancora un'altra soluzione che ho trovato in rete ... questa è sotto creativecommons e controlla se la fonte è stata inclusa prima di chiamare la funzione ...

puoi trovare il file qui: include.js

/** include - including .js files from JS - bfults@gmail.com - 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);
    }
  }   
} 

Cosa posso fare per farlo funzionare per il dominio incrociato? (caricamento script da http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

Ho appena scoperto una fantastica funzionalità di YUI 3 (al momento della scrittura disponibile nella versione di anteprima). Puoi facilmente inserire dipendenze nelle librerie YUI e nei moduli "esterni" (quello che stai cercando) senza troppo codice: YUI Loader .

Risponde anche alla seconda domanda relativa alla funzione chiamata non appena viene caricato il modulo esterno.

Esempio:

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(...);
    }
});

Ha funzionato perfettamente per me e ha il vantaggio di gestire le dipendenze. Fare riferimento alla documentazione YUI per un esempio con il calendario YUI 2 .


Questo è probabilmente l'ideale, tranne per il fatto che YUI è oscenamente grande per questa funzionalità.
Muhd,

3

C'è un nuovo standard ECMA proposto chiamato importazione dinamica , recentemente incorporato in Chrome e Safari.

const moduleSpecifier = './dir/someModule.js';

import(moduleSpecifier)
   .then(someModule => someModule.foo()); // executes foo method in someModule

2

La tecnica che usiamo al lavoro è richiedere il file javascript usando una richiesta AJAX e quindi eval () il ritorno. Se stai utilizzando la libreria di prototipi, supportano questa funzionalità nella loro chiamata Ajax.Request.


2

jquery lo ha risolto per me con la sua funzione .append () - usato per caricare l'intero pacchetto dell'interfaccia utente jquery

/*
 * 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>');
    }

Da usare - nella testa del tuo html / php / etc dopo aver importato jquery.js dovresti semplicemente includere questo file in questo modo per caricarlo in tutta la tua libreria aggiungendolo alla testa ...

<script type="text/javascript" src="project.library.js"></script>

2

Mantenerlo bello, breve, semplice e mantenibile! :]

// 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]);
    }
}

Questo codice è semplicemente un breve esempio funzionale che potrebbe richiedere funzionalità aggiuntive per il pieno supporto su qualsiasi (o data) piattaforma.


2

Importazione di moduli dinamici atterrata in Firefox 67+ .

(async () => {
   await import('./synth/BubbleSynth.js')
})()

Con gestione degli errori:

(async () => {
    await import('./synth/BubbleSynth.js').catch((error) => console.log('Loading failed' + error))
})()

Funziona anche con qualsiasi tipo di libreria non-modulo, in questo caso la lib è disponibile sull'oggetto window, alla vecchia maniera, ma solo su richiesta, il che è carino.

Esempio usando suncalc.js , il server deve avere CORS abilitato per funzionare in questo modo!

(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.sunrise.getMinutes() + ". Take your pics!")
  })
})()

https://caniuse.com/#feat=es6-module-dynamic-import


1

Esistono script progettati appositamente per questo scopo.

yepnope.js è integrato in Modernizr e lab.js è una versione più ottimizzata (ma meno user friendly).

Non consiglierei di farlo attraverso una grande libreria come jquery o prototipo - perché uno dei principali vantaggi di un caricatore di script è la capacità di caricare gli script in anticipo - non dovresti aspettare fino a quando jquery e tutti i tuoi elementi dom caricati prima eseguendo un controllo per vedere se si desidera caricare in modo dinamico uno script.


1

Ho scritto un semplice modulo che automatizza il lavoro di importazione / inclusione degli script del modulo in JavaScript. Provalo e risparmia qualche feedback! :) Per una spiegazione dettagliata del codice fare riferimento a questo post del blog: 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
});

1

Mi sono perso in tutti questi esempi, ma oggi dovevo caricare un .js esterno dal mio .js principale e ho fatto questo:

document.write("<script src='https://www.google.com/recaptcha/api.js'></script>");

puoi dare un'occhiata al link: risposta
asmmahmud

1

Eccone uno semplice con callback e supporto IE:

function loadScript(url, callback) {

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState) { //IE
        script.onreadystatechange = function () {
            if (script.readyState == "loaded" || script.readyState == "complete") {
                script.onreadystatechange = null;
                callback();
            }
        };
    } else { //Others
        script.onload = function () {
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}

loadScript("https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js", function () {

     //jQuery loaded
     console.log('jquery loaded');

});

1

So che la mia risposta è un po 'in ritardo per questa domanda, ma, ecco un grande articolo su www.html5rocks.com - Immergiti nelle acque torbide del caricamento degli script .

In quell'articolo si è concluso che per quanto riguarda il supporto del browser, il modo migliore per caricare dinamicamente il file JavaScript senza bloccare il rendering del contenuto è il seguente:

Considerando che hai quattro script nominati script1.js, script2.js, script3.js, script4.js, puoi farlo applicando async = false :

[
  '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);
});

Ora, Spec dice : Scarica insieme, esegui in ordine non appena tutto il download.

Firefox <3.6, Opera dice: Non ho idea di cosa sia questa cosa "asincrona", ma succede che eseguo gli script aggiunti tramite JS nell'ordine in cui sono stati aggiunti.

Safari 5.0 dice: Capisco "asincrono", ma non capisco impostandolo su "falso" con JS. Eseguirò i tuoi script non appena atterreranno, in qualunque ordine.

IE <10 dice: Nessuna idea di "asincrono", ma c'è una soluzione alternativa usando "onreadystatechange".

Tutto il resto dice: sono tuo amico, lo faremo dal libro.

Ora, il codice completo con IE <10 soluzione alternativa:

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

Qualche trucco e minificazione in seguito, sono 362 byte

!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"
])

Sto usando l'approccio sopra che funziona bene in Chrome e Firefox, ma sta affrontando problemi nel browser IE
Mr. Roshan

1

Qualcosa come questo...

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

1

Ecco un semplice esempio di una funzione per caricare file JS. Punti rilevanti:

  • non è necessario jQuery, quindi è possibile utilizzarlo inizialmente per caricare anche il file jQuery.js
  • è asincrono con callback
  • assicura che si carichi solo una volta, poiché mantiene un recinto con il registro degli URL caricati, evitando così l'utilizzo della rete
  • contrariamente a jQuery $.ajaxo $.getScriptè possibile utilizzare nonces, risolvendo così i problemi con CSP unsafe-inline. Basta usare la proprietàscript.nonce
var getScriptOnce = function() {

    var scriptArray = []; //array of urls (closure)

    //function to defer loading of script
    return function (url, callback){
        //the array doesn't have such url
        if (scriptArray.indexOf(url) === -1){

            var script=document.createElement('script');
            script.src=url;
            var head=document.getElementsByTagName('head')[0],
                done=false;

            script.onload=script.onreadystatechange = function(){
                if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
                    done=true;
                    if (typeof callback === 'function') {
                        callback();
                    }
                    script.onload = script.onreadystatechange = null;
                    head.removeChild(script);

                    scriptArray.push(url);
                }
            };

            head.appendChild(script);
        }
    };
}();

Ora lo usi semplicemente per

getScriptOnce("url_of_your_JS_file.js");

1

Un assurdo one-liner, per coloro che pensano che il caricamento di una libreria js non dovrebbe richiedere più di una riga di codice: P

await new Promise((resolve, reject) => {let js = document.createElement("script"); js.src="mylibrary.js"; js.onload=resolve; js.onerror=reject; document.body.appendChild(js)});

Ovviamente se lo script che vuoi importare è un modulo, puoi usare la import(...)funzione.


1

Con Promises puoi semplificarlo in questo modo. Caricatore:

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

Utilizzo (asincrono / attendi):

await loadCDN("https://.../script.js")

Utilizzo (promessa):

loadCDN("https://.../script.js").then(res => {}).catch(err => {})

NOTA: c'era una soluzione simile ma non controlla se lo script è già caricato e carica lo script ogni volta. Questo controlla la proprietà src.


0

tutte le principali librerie javascript come jscript, prototype, YUI hanno il supporto per il caricamento di file di script. Ad esempio, in YUI, dopo aver caricato il core, è possibile effettuare le seguenti operazioni per caricare il controllo del calendario

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

puoi dare un'occhiata al link: risposta
asmmahmud

0

Ho modificato alcuni dei post sopra con un esempio funzionante. Qui possiamo dare anche css e js nello stesso array.

$(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"]);
});

0

Per quelli di voi, che amano le battute singole:

import('./myscript.js');

È probabile che potresti ricevere un errore, come:

L'accesso allo script in " http: //..../myscript.js " dall'origine " http://127.0.0.1 " è stato bloccato dalla politica CORS: nessuna intestazione "Access-Control-Allow-Origin" è presente su la risorsa richiesta.

In tal caso, è possibile eseguire il fallback a:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.