Question

Comment charger un fichier JavaScript de manière fiable et dynamique ?Cela peut être utilisé pour implémenter un module ou un composant qui, une fois « initialisé », chargera dynamiquement tous les scripts de bibliothèque JavaScript nécessaires à la demande.

Le client qui utilise le composant n'est pas obligé de charger tous les fichiers de script de la bibliothèque (et d'insérer manuellement <script> balises dans leur page Web) qui implémentent ce composant - juste le fichier de script du composant « principal ».

Comment les bibliothèques JavaScript traditionnelles y parviennent-elles (Prototype, jQuery, etc.) ? Ces outils fusionnent-ils plusieurs fichiers JavaScript en une seule version « build » redistribuable d'un fichier de script ?Ou effectuent-ils un chargement dynamique des scripts de « bibliothèque » auxiliaires ?

Un ajout à cette question: existe-t-il un moyen de gérer l'événement après le chargement d'un fichier JavaScript inclus dynamiquement ? Le prototype a document.observe pour les événements à l’échelle du document.Exemple:

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

Quels sont les événements disponibles pour un élément de script ?

Était-ce utile?

La solution

Vous pouvez écrire des balises de script dynamiques (en utilisant Prototype):

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

Le problème ici est que nous ne savons pas quand le fichier de script externe est entièrement chargé.

Nous voulons souvent que notre code dépendant soit sur la ligne suivante et aimons écrire quelque chose comme :

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

Il existe un moyen intelligent d'injecter des dépendances de script sans avoir besoin de rappels.Il vous suffit d'extraire le script via un requête AJAX synchrone et évaluer le script au niveau mondial.

Si vous utilisez Prototype, la méthode Script.load ressemble à ceci :

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

Autres conseils

Il n'y a pas d'import / include / require en javascript, mais il existe deux manières principales d'obtenir ce que vous voulez :

1 - Vous pouvez le charger avec un appel AJAX puis utiliser eval.

C'est le moyen le plus simple, mais il est limité à votre domaine en raison des paramètres de sécurité Javascript, et l'utilisation d'eval ouvre la porte à des bugs et à des hacks.

2 - Ajoutez une balise de script avec l'URL du script dans le HTML.

Certainement la meilleure façon de procéder.Vous pouvez charger le script même à partir d'un serveur étranger, et il est propre lorsque vous utilisez l'analyseur du navigateur pour évaluer le code.Vous pouvez placer la balise dans l’en-tête de la page Web ou en bas du corps.

Ces deux solutions sont discutées et illustrées ici.

Maintenant, il y a un gros problème que vous devez connaître.Faire cela implique que vous chargez le code à distance.Les navigateurs Web modernes chargeront le fichier et continueront à exécuter votre script actuel car ils chargeront tout de manière asynchrone pour améliorer les performances.

Cela signifie que si vous utilisez ces astuces directement, vous ne pourrez pas utiliser votre code nouvellement chargé la ligne suivante après avoir demandé son chargement, car il sera toujours en cours de chargement.

PAR EXEMPLE :my_lovely_script.js contient 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

Ensuite, vous rechargez la page en appuyant sur F5.Et il fonctionne!Déroutant...

Alors que faire ?

Eh bien, vous pouvez utiliser le hack suggéré par l'auteur dans le lien que je vous ai donné.En résumé, pour les personnes pressées, il utilise en event pour exécuter une fonction de rappel lors du chargement du script.Vous pouvez donc mettre tout le code utilisant la bibliothèque distante dans la fonction de rappel.PAR EXEMPLE :

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

Ensuite, vous écrivez le code que vous souhaitez utiliser APRÈS que le script soit chargé dans une fonction lambda :

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

Ensuite tu lances tout ça :

loadScript("my_lovely_script.js", myPrettyCode);

OK j'ai compris.Mais c'est pénible d'écrire tout ça.

Eh bien, dans ce cas, vous pouvez utiliser comme toujours le fantastique framework gratuit jQuery, qui vous permet de faire exactement la même chose en une seule ligne :

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

J'ai utilisé un version beaucoup moins compliquée récemment avec 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>

Cela a très bien fonctionné dans tous les navigateurs dans lesquels je l'ai testé :IE6/7, Firefox, Safari, Opéra.

Mise à jour: Version sans 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>

J'ai fait essentiellement la même chose que vous avez fait Adam, mais avec une légère modification pour m'assurer que j'ajoutais à la balise head pour faire le travail.J'ai simplement créé une fonction d'inclusion (code ci-dessous) pour gérer à la fois les fichiers script et CSS.

Cette fonction vérifie également que le script ou le fichier CSS n'a pas déjà été chargé dynamiquement.Il ne vérifie pas les valeurs codées à la main et il y avait peut-être une meilleure façon de le faire, mais cela a rempli son objectif.

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

une autre réponse géniale

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

Voici un exemple de code que j'ai trouvé...quelqu'un a-t-il un meilleur moyen ?

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

Si jQuery est déjà chargé, vous devez utiliser $.getScript.

Cela présente un avantage par rapport aux autres réponses ici dans la mesure où vous disposez d'une fonction de rappel intégrée (pour garantir que le script est chargé avant l'exécution du code dépendant) et que vous pouvez contrôler la mise en cache.

quelqu'un a-t-il un meilleur moyen ?

Je pense qu'il serait plus facile d'ajouter simplement le script au corps que de l'ajouter au dernier nœud de la page.Que dis-tu de ça:

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

j'ai encore utilisé une autre solution trouvée sur le net...celui-ci est sous creativecommons et il vérifie si la source a été incluse avant d'appeler la fonction ...

vous pouvez trouver le fichier ici: inclure.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);
    }
  }   
} 

Je viens de découvrir une fonctionnalité intéressante dans YUI 3 (au moment de la rédaction, disponible en version préliminaire).Vous pouvez facilement insérer des dépendances aux bibliothèques YUI et aux modules "externes" (ce que vous recherchez) sans trop de code : Chargeur YUI.

Il répond également à votre deuxième question concernant la fonction appelée dès que le module externe est chargé.

Exemple:

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

A parfaitement fonctionné pour moi et a l'avantage de gérer les dépendances.Reportez-vous à la documentation YUI pour un exemple avec le calendrier YUI 2.

Si tu veux un SYNCHRONISATION Lors du chargement du script, vous devez ajouter le texte du script directement à la balise HTML HEAD.L'ajouter comme déclenchera un ASYNC charger.Pour charger le texte du script à partir d'un fichier externe de manière synchrone, utilisez XHR.Ci-dessous un échantillon rapide (il utilise des parties d'autres réponses dans ce message et dans d'autres) :

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

La technique que nous utilisons au travail consiste à demander le fichier javascript à l'aide d'une requête AJAX, puis à eval() le retour.Si vous utilisez la bibliothèque de prototypes, ils prennent en charge cette fonctionnalité dans leur appel Ajax.Request.

jquery a résolu ce problème pour moi avec sa fonction .append()- utilisé ceci pour charger le package complet de l'interface utilisateur 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>');
    }

Utiliser - dans l'en-tête de votre html/php/etc après avoir importé jquery.js, vous incluez simplement ce fichier comme ceci pour le charger dans l'intégralité de votre bibliothèque en l'ajoutant à l'en-tête...

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

Gardez-le agréable, court, simple et maintenable !:]

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

Ce code est simplement un court exemple fonctionnel qui pourrait nécessitent des fonctionnalités supplémentaires pour une prise en charge complète sur n'importe quelle plate-forme (ou donnée).

Il existe une nouvelle norme ECMA proposée appelée importation dynamique, récemment intégré à Chrome et Safari.

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

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

Il existe des scripts spécialement conçus à cet effet.

ouais.js est intégré à Modernizr, et laboratoire.js est une version plus optimisée (mais moins conviviale).

Je ne recommanderais pas de le faire via une grande bibliothèque comme jquery ou prototype - car l'un des principaux avantages d'un chargeur de script est la possibilité de charger des scripts plus tôt - vous ne devriez pas avoir à attendre que jquery et tous vos éléments dom se chargent avant exécuter une vérification pour voir si vous souhaitez charger dynamiquement un script.

J'ai écrit un module simple qui automatise le travail d'importation/inclusion de scripts de module en JavaScript.Essayez-le et n'hésitez pas à nous faire part de vos commentaires !:) Pour une explication détaillée du code, reportez-vous à ce billet de 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
});

Je suis perdu dans tous ces exemples mais aujourd'hui j'avais besoin de charger un .js externe à partir de mon .js principal et j'ai fait ceci :

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

Ici est simple avec rappel et prise en charge d'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');

});

Voici un exemple simple de fonction permettant de charger des fichiers JS.Points pertinents :

  • vous n'avez pas besoin de jQuery, vous pouvez donc l'utiliser initialement pour charger également le fichier jQuery.js
  • c'est asynchrone avec le rappel
  • il garantit qu'il ne se charge qu'une seule fois, car il conserve une pièce jointe avec l'enregistrement des URL chargées, évitant ainsi l'utilisation du réseau
  • contrairement à jQuery $.ajax ou $.getScript vous pouvez utiliser des noms occasionnels, résolvant ainsi les problèmes avec CSP unsafe-inline.Utilisez simplement la propriété 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);
        }
    };
}();

Maintenant, vous l'utilisez simplement en

getScriptOnce("url_of_your_JS_file.js");

Un one-liner absurde, pour ceux qui pensent que charger une bibliothèque js ne devrait pas prendre plus d'une ligne de code :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)});

Évidemment, si le script que vous souhaitez importer est un module, vous pouvez utiliser le import(...) fonction.

toutes les principales bibliothèques javascript comme jscript, prototype, YUI prennent en charge le chargement de fichiers de script.Par exemple, dans YUI, après avoir chargé le noyau, vous pouvez procéder comme suit pour charger le contrôle du calendrier

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

Je sais que ma réponse est un peu tardive à cette question, mais voici un excellent article dans www.html5rocks.com - Plongez en profondeur dans les eaux troubles du chargement de scripts .

Dans cet article, il est conclu qu'en ce qui concerne la prise en charge du navigateur, la meilleure façon de charger dynamiquement un fichier JavaScript sans bloquer le rendu du contenu est la suivante :

Considérant que vous avez quatre scripts nommés script1.js, script2.js, script3.js, script4.js alors tu peux le faire avec appliquer 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);
});

Maintenant, Spécification dit:Téléchargez ensemble, exécutez dans l'ordre dès que tout est téléchargé.

Firefox < 3.6, Opera dit : Je n'ai aucune idée de ce qu'est cette chose "asynchrone", mais il se trouve que j'exécute des scripts ajoutés via JS dans l'ordre dans lequel ils sont ajoutés.

Safari 5.0 dit : Je comprends « async », mais je ne comprends pas le définir sur « false » avec JS.J'exécuterai vos scripts dès leur arrivée, dans n'importe quel ordre.

IE < 10 dit : Aucune idée sur « async », mais il existe une solution de contournement en utilisant « onreadystatechange ».

Tout le reste dit : Je suis ton ami, nous allons faire ça selon les règles.

Maintenant, le code complet avec la solution de contournement IE < 10 :

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

Quelques astuces et minifications plus tard, ça fait 362 octets

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

Quelque chose comme ça...

<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>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top