Wie verwende ich when dann, um den Datei-Upload sequentiell in einer Funktion zu senden, die auch ein verzögertes Versprechen ist?

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

Frage

Ich beabsichtige, eine Reihe von Dateien mit jQuery hochzuladen.

Diese Absicht wird in eine aufgerufene Funktion verpackt uploadFilesUsingAjax();

var uploadFilesPromise = uploadFilesUsingAjax();

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

Ich muss warten, bis alle Dateien erfolgreich hochgeladen wurden, bevor ich etwas anderes tun kann.

Innen uploadFilesUsingAjax(),

Ich habe meinen Code so geschrieben

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

Leider konnte ich nicht viele Dateien hochladen, bevor ich zur Erfolgsseite weitergeleitet wurde.

Ich habe verschiedene StackOverflow-Lösungen ausprobiert, wie das geht.Bisher funktioniert nichts.Bitte beraten.

Aus Platzgründen wurde ein Teil des Codes gekürzt.

War es hilfreich?

Lösung

Alle Ihre Versprechen sind parallel und nicht sequentiell.

Ein Versprechen stellt eine dar läuft bereits Aufgabe.Versprechen in JavaScript sind im Gegensatz zu C#-Aufgaben oder anderen Abstraktionen bereits gestartet.Die Darstellung einer noch nicht gestarteten Aufgabe erfolgt über eine Funktion, die ein Versprechen zurückgibt.

Seit promises[i] ist bereits ein Versprechen – wenn Sie es tun promise.then(object) Es wird kein .then-Handler hinzugefügt, sondern es wird sofort zurückgegeben. .then ignoriert alle Argumente, die keine Funktion sind.

Deshalb kehrt es früh zurück, es kehrt zurück, sobald das erste Versprechen erfüllt ist.Du brauchst das auch nicht .when.Erstellen Sie eine Funktion, die einen Upload-Prozess als solchen erstellt:

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

Jetzt können Sie die Dateien Aufgaben zuordnen:

 var tasks = files.map(createUploadTask);

Beachten Sie, dass jetzt die Aufgaben jeweils sind Funktionen die ein Versprechen über einen Datei-Upload zurückgeben.Es sind keine Versprechen.

Jetzt können Sie sie verketten:

 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;

Sie müssen jetzt auch nicht when verwenden, da Sie a zurückgeben einzel versprechen.Ich gehe davon aus, dass Sie hier nicht das tatsächliche Ergebnis benötigen (sondern nur, um Erfolg/Misserfolg zu erfahren).

Sie tun einfach:

 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; 
 }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top