2012-10-26 1 views
1

Je dois exécuter un nombre arbitraire de scripts. Le prochain peut exécuter seulement du précédent a chargé et exécuté. Je sais RequireJS (et connexes) seraient le bon choix, mais je suis en train d'apprendre au sujet des promesses, donc voici mon expérience:Exécution séquentielle d'un nombre arbitraire de scripts en utilisant map/reduce et jQuery

var files = [ 
    'first.js', 
    'second.js', 
    'third.js', 
    'fourth.js' 
]; 

var funcs = files.map(function(file) { 
    return function() { return $.getScript(file); } 
}); 

var deferred = $.Deferred(); 

funcs.reduce(function (soFar, f) { 
    return soFar.then(f); 
}, deferred.resolve(funcs[0])); 

Quelqu'un peut-il expliquer les pièges et les solutions de rechange à ma solution?

Répondre

1

Qu'est-ce que vous cherchez vraiment est .pipe (ou 1.8+, je crois .alors a été changé pour signifier la même chose)

En bref, le tuyau vous permettra de promesses de la chaîne de la manière que vous cherchons. Le code pourrait ressembler à ceci (non testé):

var files, scriptsLoaded; 

files = [ 'first.js', 'second.js', 'third.js', 'fourth.js' ]; 

while(files.length) { 
    (function() { 
     var currentUrl = files.shift(); 

     scriptsLoaded = scriptsLoaded ? 
      scriptsLoaded.pipe(function() { 
       return $.getScript(currentUrl); 
      }) : 
      $.getScript(currentUrl); 
    }()); 
} 

$.when(scriptsLoaded).done(function() { 
    // All scripts are now loaded assuming none of them failed 
}); 

** Modifier **

Avec ce lien que vous avez fourni, je comprends ce que vous essayez d'accomplir. Voici une version corrigée de votre solution avec quelques commentaires. Il accomplit la même chose que l'autre solution, mais c'est une version beaucoup plus concise:

var files = [ 'first.js', 'second.js', 'third.js', 'fourth.js' ]; 

// The initial value provided to the reduce function is a promise 
// that will resolve when the first file has been loaded. For each 
// of the remaining file names in the array, pipe it through that first 
// promise so that the files are loaded in sequence (chained). 
// The value that is returned from the reduce function is a promise 
// that will resolve only when the entire chain is done loading. 
var scriptsLoaded = files.slice(1).reduce(function (soFar, file) { 
    return soFar.pipe(function() { 
     return $.getScript(file); 
    }); 
}, $.getScript(files[0]); 
+0

Cela a fonctionné très bien, merci! (essayant toujours de comprendre l'usage de "pipe"). Diriez-vous que cette approche est meilleure ou que les deux sont acceptables? – sigmus

+0

Le problème avec l'approche originale est que "différé" est immédiatement résolu plutôt que d'être résolu lorsque toutes les demandes sont terminées. En utilisant .pipe, le différé renvoyé est résolu uniquement lorsque la chaîne entière réussit ou échoue. Ma solution peut probablement être rendue plus concise, mais il faudrait quand même utiliser un tuyau pour enchaîner les tâches - voir http://api.jquery.com/deferred.pipe/#example-2 – dherman

+0

Merci beaucoup! J'ai fait quelques expériences et avec mon code, si une force 404 dans "second.js" le reste des fichiers ne sont pas appelés. Mon exemple a été adapté à partir d'ici https://github.com/kriskowal/q#sequences – sigmus

Questions connexes