Charger dynamiquement un fichier JavaScript


168

Comment pouvez-vous charger de manière fiable et dynamique un fichier JavaScript? 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 bibliothèque (et d'insérer manuellement des <script>balises dans sa page Web) qui implémentent ce composant - juste le fichier de script du composant «principal».

Comment les bibliothèques JavaScript grand public accomplissent-elles cela (Prototype, jQuery, etc.)? Ces outils fusionnent-ils plusieurs fichiers JavaScript en une seule version «build» redistribuable d'un fichier de script? Ou font-ils un chargement dynamique de 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? Prototype a document.observepour 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?


Réponses:


84

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 complètement chargé.

Nous voulons souvent notre code dépendant 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. Vous devez simplement extraire le script via une requête AJAX synchrone et évaluer le script au niveau global.

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

Que puis-je faire pour le faire fonctionner pour le cross-domain? (chargement du script depuis http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570


@Ciastopiekarz: Je ne contrôle pas web.archive.org.
user2284570

Ensuite, vous devez gratter les données auxquelles vous souhaitez accéder en utilisant un autre programme et vous les fournir
David Schumann

qu'est-ce que Ajax.Request ??
bluejayke

72

Il n'y a pas d'import / include / require en javascript, mais il existe deux façons 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 utiliser eval ouvre la porte aux bogues et aux hacks.

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

Certainement la meilleure voie à suivre. 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 mettre la balise dans la 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. Cela implique que vous chargez le code à distance. Les navigateurs Web modernes chargeront le fichier et continueront à exécuter votre script actuel car ils chargent 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.

EG: 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 à ce sujet?

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 lorsque le script est chargé. Ainsi, vous pouvez mettre tout le code à l'aide de 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 le chargement du script dans une fonction lambda:

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

Ensuite, vous exécutez tout cela:

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 jQuery gratuit, 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
});

11
Je ne peux pas croire à quel point cette réponse est sous-estimée. Je vous remercie.
naftalimich

2
Je parie que c'est parce que les gens n'aiment pas lire au-delà de la première ligne, à moins que cela ne leur promette qu'ils seront riches s'ils «suivent simplement ces trois étapes secrètes pour réussir».
Costa

Cela marche. J'espère que partager mon expérience ici vous fera gagner du temps car j'ai passé de nombreuses heures là-dessus. J'utilise Angular 6 et un modèle appliqué (html, css, jquery) Le problème est que le modèle a un fichier js qui se charge après le chargement des éléments html pour attacher les événements des écouteurs. Ce fichier js était difficile à exécuter après le chargement de l'application angulaire. L'ajouter à la balise de scripts angular app (angular.json) les regroupera mais n'exécutera pas ce fichier js après le chargement. Il y a trop de code à réécrire en tapuscrit, donc cela a été d'une grande aide. Commentaire suivant Je vais mettre l'exemple en raison de la longueur du commentaire
Nour Lababidi

J'ai simplement utilisé ce code comme suit: ngAfterViewInit () {debugger; $ .getScript ("/ assets / js / jquery.app.js", function () {alert ("Script chargé et exécuté."); // ici vous pouvez utiliser tout ce que vous avez défini dans le script chargé}); }
Nour Lababidi

Pour le '$' en angulaire, j'ai suivi ceci: stackoverflow.com/questions/32050645/...
Nour Lababidi

28

J'ai utilisé une 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 fonctionnait très bien dans tous les navigateurs dans lesquels je l'ai testé: IE6 / 7, Firefox, Safari, Opera.

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>

25
C'est génial ... sauf si vous essayez de charger jquery.

1
On dirait que jQuery va intégrer le plugin Require dans jQuery Core pour une version future: plugins.jquery.com/project/require
Adam

1
Une manière encore meilleure d'utiliser jQuery est d'utiliser $.getScript. Voyez ma réponse.
Muhd

1
Modernizr (yepnope.js) ou lab.js sont les solutions appropriées pour cela. l'utilisation d'une bibliothèque de scripts lourde (qui doit se charger en premier) n'est pas la réponse la plus appropriée pour les mobiles ou de nombreuses autres situations.
1nfiniti le

2
Les anciens navigateurs et validateurs html @MaulikGangani interpréteraient cela comme le jeton pour terminer le script.
travis

20

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 à l'étiquette de tête pour faire le travail. J'ai simplement créé une fonction include (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 servi le but.

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

Sans plus de contexte que ce Pickle, j'ai bien peur de ne pas avoir de suggestions. Le code ci-dessus fonctionne tel quel, il a été extrait directement d'un projet opérationnel.
palehorse

5
@palehorse, Mike et Muhd, ont raison, cela pourrait fonctionner dans votre projet, mais c'est parce que les variables "includedFile" et "Array" doivent être définies ailleurs dans votre projet, ce code ne fonctionnera pas seul, il pourrait être mieux vaut le modifier pour qu'il puisse fonctionner en dehors du contexte de votre projet, ou au moins ajouter un commentaire expliquant quelles sont ces variables non définies (type etc)
user280109

14

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


2
Que puis-je faire pour le faire fonctionner pour le cross-domain? (chargement du script depuis http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

9

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

Que puis-je faire pour le faire fonctionner pour le cross-domain? (chargement du script depuis http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

6

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

Cela présente un avantage par rapport aux autres réponses ici en ce sens que 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.


4

Si vous souhaitez charger un script SYNC , vous devez ajouter le texte du script directement à la balise HTML HEAD. L'ajouter comme déclenchera une charge ASYNC . Pour charger le texte de script à partir d'un fichier externe de manière synchrone, utilisez XHR. Ci-dessous un exemple rapide (il utilise des parties d'autres réponses dans cet article 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()); });

3

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

Que puis-je faire pour le faire fonctionner pour le cross-domain? (chargement du script depuis http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

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

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

Que puis-je faire pour le faire fonctionner pour le cross-domain? (chargement du script depuis http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js)
user2284570

3

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

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 .


C'est probablement idéal, sauf que YUI est extrêmement volumineux pour cette fonctionnalité.
Muhd

3

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

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

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

2

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.


2

jquery a résolu cela 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 la tête de votre html / php / etc après avoir importé jquery.js, vous incluriez simplement ce fichier pour le charger dans l'intégralité de votre bibliothèque en l'ajoutant à la tête ...

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

2

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écessiter des fonctionnalités supplémentaires pour une prise en charge complète sur n'importe quelle plate-forme (ou donnée).


2

L' importation de modules dynamiques a atterri dans Firefox 67+ .

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

Avec gestion des erreurs:

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

Cela fonctionne également pour tout type de bibliothèques non-modules, dans ce cas, la lib est disponible sur l'objet window, à l'ancienne, mais uniquement à la demande, ce qui est bien.

Exemple utilisant suncalc.js , le serveur doit avoir CORS activé pour fonctionner de cette façon!

(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

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

yepnope.js est intégré à Modernizr et lab.js est une version plus optimisée (mais moins conviviale.

Je ne recommanderais pas de faire cela 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 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.


1

J'ai écrit un module simple qui automatise le travail d'importation / inclusion de scripts de module en JavaScript. Essayez-le et faites-nous 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
});

1

Je suis perdu dans tous ces échantillons, 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>");

vous pouvez consulter le lien: réponse
asmmahmud

1

En voici un simple avec rappel et support 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

Je sais que ma réponse est un peu tardive à cette question, mais voici un excellent article sur www.html5rocks.com - Plongez 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:

Étant donné que vous avez nommé quatre scripts, script1.js, script2.js, script3.js, script4.jsvous pouvez le faire en appliquant 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, Spec dit : Téléchargez ensemble, exécutez dans l'ordre dès que tous les téléchargements.

Firefox <3.6, Opera dit: Je n'ai aucune idée de ce qu'est ce truc «asynchrone», mais il se trouve que j'exécute les 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 «faux» avec JS. J'exécuterai vos scripts dès leur arrivée, dans n'importe quel ordre.

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

Tout le reste dit: je suis votre ami, nous allons le faire par le livre.

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 minification plus tard, c'est 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"
])

J'utilise l'approche ci-dessus, cela fonctionne bien dans Chrome et Firefox, mais face à des problèmes dans le navigateur IE
M. Roshan

1

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>

1

Voici un exemple simple de fonction pour charger des fichiers JS. Points importants:

  • vous n'avez pas besoin de jQuery, vous pouvez donc l'utiliser initialement pour charger également le fichier jQuery.js
  • c'est asynchrone avec rappel
  • il assure qu'il ne se charge qu'une seule fois, car il conserve une clôture avec l'enregistrement des URL chargées, évitant ainsi l'utilisation du réseau
  • contrairement à jQuery $.ajaxou $.getScriptvous pouvez utiliser des nonces, 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");

1

Un one-liner absurde, pour ceux qui pensent que le chargement d'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 la import(...)fonction.


1

Avec Promises, vous pouvez le simplifier comme ça. Fonction chargeur:

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

Utilisation (async / wait):

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

Utilisation (promesse):

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

REMARQUE: il y avait une solution similaire mais elle ne vérifie pas si le script est déjà chargé et charge le script à chaque fois. Celui-ci vérifie la propriété src.


0

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 effectuer les opérations suivantes pour charger le contrôle de 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();

vous pouvez consulter le lien: réponse
asmmahmud

0

J'ai peaufiné certains des articles ci-dessus avec un exemple de travail. Ici, nous pouvons également donner css et js dans le même tableau.

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

Pour ceux d'entre vous qui aiment les one-liners:

import('./myscript.js');

Il y a de fortes chances que vous obteniez une erreur, comme:

L'accès au script à ' http: //..../myscript.js ' à partir de l'origine ' http://127.0.0.1 ' a été bloqué par la stratégie CORS: aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée.

Dans ce cas, vous pouvez revenir à:

fetch('myscript.js').then(r => r.text()).then(t => new Function(t)());
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.