jQuery: charger les scripts dans l'ordre

je suis en train de charger des scripts de façon dynamique avec jQuery:

var scripts = ['script1.js','script2.js','script3.js'];

$.each(scripts , function(i, val) {
     $.getScript(val, function() {
     console.log('loaded '+ val);
});

mais parfois l'ordre des scripts chargés change. Comment puis-je charger chaque script après que le précédent a été chargé avec succès?

10
demandé sur Jasper 2012-03-15 02:18:34

6 réponses

vous pouvez charger chacun d'eux une fois que le chargement précédent est terminé en utilisant la fonction de rappel de $.getScript() comme appel de fonction récursif.

//setup array of scripts and an index to keep track of where we are in the process
var scripts = ['script1.js','script2.js','script3.js'],
    index   = 0;

//setup a function that loads a single script
function load_script() {

    //make sure the current index is still a part of the array
    if (index < scripts.length) {

        //get the script at the current index
        $.getScript(scripts[index], function () {

            //once the script is loaded, increase the index and attempt to load the next script
            console.log('Loaded: ' + scripts[index]);
            index++;
            load_script();
        });
    }
}

ce qui se passe dans votre code est que les scripts sont demandés en même temps et puisqu'ils se chargent de façon asynchrone, ils reviennent et s'exécutent dans un ordre aléatoire.

mise à Jour

Je n'ai pas testé cela, mais si les scripts sont hébergés localement, alors vous pouvez essayer de les récupérer en texte clair, puis stocker tout le code de variables jusqu'à ce qu'ils sont tous chargés à laquelle vous pourriez évaluer les scripts dans l'ordre:

var scripts   = ['script1.js','script2.js','script3.js'],

    //setup object to store results of AJAX requests
    responses = {};

//create function that evaluates each response in order
function eval_scripts() {
    for (var i = 0, len = scripts.length; i < len; i++) {
        eval(responses[scripts[i]]);
    }
}

$.each(scripts, function (index, value) {
    $.ajax({
        url      : scripts[index],

        //force the dataType to be `text` rather than `script`
        dataType : 'text',
        success  : function (textScript) {

            //add the response to the `responses` object
            responses[value] = textScript;

            //check if the `responses` object has the same length as the `scripts` array,
            //if so then evaluate the scripts
            if (responses.length === scripts.length) { eval_scripts(); }
        },
        error    : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ }
    });
});
17
répondu Jasper 2012-03-14 22:32:41

vous faites usage du fait le jqXhr objet retournée par $.getScript (et toutes les autres méthodes Ajax) implémente l'interface Promise et fournit donc .pipe() qui peut être utilisé pour enchaîner des objets différés:

var deferred = new $.Deferred(),
    pipe = deferred;

$.each(scripts , function(i, val) {
     pipe = pipe.pipe(function() {
         return  $.getScript(val, function() {
             console.log('loaded '+ val);
         });
     });
});

deferred.resolve();

pour plus d'information, consultez différés objets et deferred.pipe.

dans l'ensemble, l'utilisation d'objets différés vous donne une plus grande flexibilité et pourrait vous permettre d'ajouter des gestionnaires d'erreurs plus facilement.

10
répondu Felix Kling 2012-03-14 22:35:43

amélioré version de la solution de @Jasper:

  • en utilisant $.when pour synchroniser les appels.
  • à l'aide d'un global eval.

Voici le code:

/**
 * Load scripts in parallel keeping execution order.
 * @param {array} An array of script urls. They will parsed in the order of the array.
 * @returns {$.Deferred}
 */
function getScripts(scripts) {
    var xhrs = scripts.map(function(url) {
        return $.ajax({
            url: url,
            dataType: 'text',
            cache: true
        });
    });

    return $.when.apply($, xhrs).done(function() {
        Array.prototype.forEach.call(arguments, function(res) {
            eval.call(this, res[0]);
        });
    });
}

résumé: https://gist.github.com/ngryman/7309432.

2
répondu ngryman 2017-03-18 14:50:46

certains scripts peuvent varier en taille, donc c'est imprévisible. Essayez quelque chose comme ça.

var scripts = ['script1.js','script2.js','script3.js'], ScriptIndex = 0;
function LoadScript(index){
    if(index >= scripts.length)
        return;

    $.getScript(scripts[index], function(){
        console.log('Loaded script '+ scripts[index]);
        LoadScript(++ScriptIndex);
    }
}

Cela devrait charger chaque script après le dernier est complètement chargé. Assurez-vous de le démarrer en appelant la fonction LoadScript(0);

1
répondu Austin Brunkhorst 2012-03-14 22:27:31

Vous pouvez trier () le tableau -

var sorted = scripts.sort();

et ensuite utiliser trié dans votre chaque fonction.

0
répondu Jay Blanchard 2012-03-14 22:23:11

il y a un petit problème avec la solution de @ngryman; s'il n'y a qu'une seule url dans le tableau des URL à charger, la .done () arguments de la fonction param sera un tableau unidimensionnel, plutôt que 2 dimensionnel. Vous aurez besoin de vérifier les arguments avant de passer à travers, ainsi:

/**
 * Load scripts in parallel keeping execution order.
 * @param {array} An array of script urls. They will parsed in the order of the array.
 * @returns {$.Deferred}
 */
function getScripts(scripts) {
    var xhrs = scripts.map(function(url) {
        return $.ajax({
            url: url,
            dataType: 'text',
            cache: true
        });
    });

    return $.when.apply($, xhrs).done(function() {
        if (arguments.length == 3 && typeof arguments[0] == "string") {
            arguments = [arguments];
        }
        Array.prototype.forEach.call(arguments, function(res) {
            eval.call(this, res[0]);
        });
    });
}

excuses pour la nouvelle réponse, pas assez de rep pour poster un commentaire sur la réponse de @ngryman, mais j'ai pensé que cela pourrait aider quelqu'un!

0
répondu Ben 2018-04-05 10:36:11