66 votes

Chargement dynamique de JavaScript de manière synchrone

J'utilise le modèle de module. Je souhaite notamment inclure de manière dynamique un fichier JavaScript externe, l'exécuter, puis utiliser les fonctions / variables du fichier dans le return { } de mon module. .

Je n'arrive pas à comprendre comment faire cela facilement. Existe-t-il des méthodes standard pour effectuer un chargement de script externe pseudo-synchrone?

 function myModule() {
    var tag = document.createElement("script");
    tag.type = "text/javascript";
    tag.src = "http://some/script.js";
    document.getElementsByTagName('head')[0].appendChild(tag);

    //something should go here to ensure file is loaded before return is executed

    return {
        external: externalVariable 
    }
}
 

55voto

Sean Kinsey Points 17117

Il n'y a qu'un seul moyen de charger et d'exécuter de manière synchrone une ressource de script, à savoir utiliser un XHR synchrone

Ceci est un exemple de comment faire cela

 // get some kind of XMLHttpRequest
var xhrObj = createXMLHTTPObject();
// open and send a synchronous request
xhrObj.open('GET', "script.js", false);
xhrObj.send('');
// add the returned content to a newly created script tag
var se = document.createElement('script');
se.type = "text/javascript";
se.text = xhrObj.responseText;
document.getElementsByTagName('head')[0].appendChild(se);
 

Mais vous ne devriez pas en général utiliser des requêtes synchrones car cela bloquerait tout le reste. Cela étant dit, il existe bien sûr des scénarios dans lesquels cela est approprié.

Je refacturerais probablement la fonction contenant dans un modèle asynchrone, bien que j'utilise un gestionnaire de chargement onload.

47voto

Neil Points 62

L'on a accepté la réponse n'est PAS correcte.

Chargement d'un fichier en mode synchrone n'est pas la même que l'exécution du fichier de manière synchrone - qui est ce que l'OP a demandé.

La accepté de répondre à charge la synchronisation de fichiers, mais ne fait rien de plus que d'ajouter une balise de script pour les DOM. Tout simplement parce que appendChild() a retourné n'est pas en aucune façon la garantie que le script a fini de s'exécuter et de ses membres sont initialisées à l'utilisation.

Le seul (voir mise en garde) pour atteindre le OPs question est de sync charger le script sur XHR comme indiqué, puis de lire que le texte et les passer dans la fonction eval() ou une nouvelle Fonction() appeler et d'attendre que la fonction de retour. C'est la seule façon de garantir que le script est chargé ET exécuté de manière synchrone.

Je ne ferai aucun commentaire quant à savoir si c'est une chose sage à faire soit à partir d'une INTERFACE utilisateur ou un point de vue sécurité, mais il y a certainement des cas d'utilisation qui justifient d'une synchronisation de chargement et exécution.

Mise en garde: Sauf si vous êtes en utilisant des web workers auquel cas il suffit de l'appeler loadScripts();

10voto

Alan Joseph Points 71

C'est le code que j'utilise pour le chargement de plusieurs fichiers dans mon application.

 Utilities.require = function (file, callback) {
    callback = callback ||
    function () {};
    var filenode;
    var jsfile_extension = /(.js)$/i;
    var cssfile_extension = /(.css)$/i;

    if (jsfile_extension.test(file)) {
        filenode = document.createElement('script');
        filenode.src = file;
        // IE
        filenode.onreadystatechange = function () {
            if (filenode.readyState === 'loaded' || filenode.readyState === 'complete') {
                filenode.onreadystatechange = null;
                callback();
            }
        };
        // others
        filenode.onload = function () {
            callback();
        };
        document.head.appendChild(filenode);
    } else if (cssfile_extension.test(file)) {
        filenode = document.createElement('link');
        filenode.rel = 'stylesheet';
        filenode.type = 'text/css';
        filenode.href = file;
        document.head.appendChild(filenode);
        callback();
    } else {
        console.log("Unknown file type to load.")
    }
};

Utilities.requireFiles = function () {
    var index = 0;
    return function (files, callback) {
        index += 1;
        Utilities.require(files[index - 1], callBackCounter);

        function callBackCounter() {
            if (index === files.length) {
                index = 0;
                callback();
            } else {
                Utilities.requireFiles(files, callback);
            }
        };
    };
}();
 

Et ces utilitaires peuvent être utilisés par

 Utilities.requireFiles(["url1", "url2",....], function(){
    //Call the init function in the loaded file.
    })
 

3voto

2astalavista Points 7092
 var xhrObj = new XMLHttpRequest();
xhrObj.open('GET', '/filename.js', false);
xhrObj.send(null);
eval(xhrObj.responseText);
 

S'il s'agit d'une demande interdomaine, cela ne fonctionnera pas. Dans ce cas, vous devez télécharger le fichier demandé sur votre serveur ou créer un miroir php qui le restitue et l'exiger.

Avec jquery (fonctionne également avec les requêtes interdomaines):

 $.getScript('/filename.js',callbackFunction);
 

callbackFunction seront appelés de manière synchrone.

Pour charger plus de scripts, voir ce fil.

1voto

Jason Points 20255

consultez cette page en Javascript haute performance

En gros, vous lui indiquez le script à charger, puis vous pouvez lui attribuer une fonction de rappel à exécuter une fois que c'est fait. Je l'utilise en production et c'est génial.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X