Comment utiliser when then pour envoyer le téléchargement de fichiers de manière séquentielle dans une fonction qui est également une promesse différée ?

StackOverflow https://stackoverflow.com//questions/23065705

Question

J'ai l'intention de télécharger un tableau de fichiers en utilisant jQuery.

Cette intention est enveloppée dans une fonction appelée uploadFilesUsingAjax();

var uploadFilesPromise = uploadFilesUsingAjax();

$.when(uploadFilesPromise).done(function (uploadFilesAjaxResult) {
        // redirect to success page...

Je dois attendre que tous les fichiers soient téléchargés avec succès avant de faire autre chose.

À l'intérieur uploadFilesUsingAjax(),

J'ai écrit mon code de cette façon

function uploadFilesUsingAjax() {
    var files = pages; // pages is a global variable which is an array of files
    var url = "/users/" + currentUser.id + "/files.json";
    var type = "POST";

    console.info('files length:' + files.length);
    if (files.length > 0) {

        var promises=[];
        for (var i = 0; i < files.length; i++) {
            var data = new FormData();
            var postData = {};
            var file = files.getByIndex(i);
            var key = i + 1;
            if (typeof (file.id) !== "undefined" && file.id > 0) {
                data.append(key, JSON.stringify(file));
            } else {
                data.append(key, file);
            }
            var request = $.ajax({
                //this is the php file that processes the data 
                url: url,

                //POST method is used
                type: type,

                //pass the data
                data: data,

                //Do not cache the page
                cache: false,

                xhr: function() {
                    // custom xhr
                    myXhr = $.ajaxSettings.xhr();
                    if(myXhr.upload) { // check if upload property exists

                            myXhr.upload.addEventListener('progress',updatePagesProgress, false); // for handling the progress of the upload
                    }
                    return myXhr;
                },

                // DO NOT set the contentType and processData
                // see http://stackoverflow.com/a/5976031/80353
                contentType: false,
                processData: false,

                //success
                success: function (json) {
                    // json is already an object thanks to cakephp code to serialize

                    //if POST is a success expect no errors
                    if (json.error == null && json.result != null) {
                        currentUser = json.result.User;
                    // error
                    } else {
                        alert(json.error);
                    }
                }
            });
            promises.push( request);
        }

        var promise = promises[0];
        for (var i = 1; i < promises.length; i++) {
          promise = promise.then(promises[i]);
        }

        return promise.done(function () { console.log('all!')});

Malheureusement, je n'ai pas pu télécharger beaucoup de fichiers avant d'être redirigé vers la page de réussite.

J'ai essayé diverses solutions StackOverflow pour savoir comment procéder.Jusqu'à présent, rien ne fonctionne.S'il vous plaît aviser.

Certains codes ont été tronqués pour gagner de la place.

Était-ce utile?

La solution

Toutes vos promesses sont parallèles et non séquentielles.

Une promesse représente un déjà en train de courir tâche.Les promesses en JavaScript, contrairement aux tâches C# ou autres abstractions, sont déjà démarrées.La façon de représenter une tâche qui n’a pas démarré est une fonction renvoyant une promesse.

Depuis promises[i] est déjà une promesse - quand tu le fais promise.then(object) il n'ajoute pas de gestionnaire .then mais revient plutôt immédiatement. .then ignore tous les arguments qui ne sont pas une fonction.

C'est pourquoi il revient tôt, il revient dès que la première promesse s'accomplit.Vous n'avez pas non plus besoin du .when.Créez une fonction qui crée un processus de téléchargement en tant que tel :

function createUploadTask(file,i){
    return function(){
         var data = new FormData();
         var postData = {};
         var file = files.getByIndex(i);
         var key = i + 1;
         if (typeof (file.id) !== "undefined" && file.id > 0) {
             data.append(key, JSON.stringify(file));
         } else {
             data.append(key, file);
         }
         return $.ajax({...}); // return the promise
   }
}

Maintenant, vous pouvez mapper les fichiers aux tâches :

 var tasks = files.map(createUploadTask);

Notez que maintenant les tâches sont chacune les fonctions qui renvoient une promesse lors d'un téléchargement de fichier.Ce ne sont pas des promesses.

Maintenant, vous pouvez les enchaîner :

 var p = tasks[0](); // start off the chain
 for(var i = 1; i < tasks.length; i++){
      // chain the next task, note, that we're passing a _function_ here
      // when you return a promise from a `.then` it will fulfill when that promise 
      // fulfills, in our case the $.ajax
      p = p.then(tasks[i]); 
 }
 return p;

De plus, vous n'avez plus besoin d'utiliser when, puisque vous renvoyez un célibataire promesse.Je suppose que vous n'avez pas besoin du résultat réel ici (mais seulement pour connaître le succès/l'échec).

Vous faites simplement :

 function uploadFilesUsingAjax() {
     // settings
     if(tasks.length === 0){
          // a method MUST always either return either synchronously or asynchronously never
          // both, always return a promise. Otherwise you get API hell.
          var d = $.Deferred();
          d.reject(new Error("Called uploadFiles with no files to upload"));
          return d.promise;
     }
     tasks = pages.map(createUploadTask)
     var p = tasks[0](); // call first one
     for(var i = 1; i < tasks.length; i++) p = p.then(tasks[i]);
     return p; 
 }
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top