2014-04-14 7 views
5

Ich beabsichtige, ein Array von Dateien mit jQuery hochzuladen.Wie zu verwenden, wenn dann Datei-Upload sequenziell in einer Funktion senden, die auch ein verzögertes Versprechen ist?

Diese Absicht ist in eine Funktion namens uploadFilesUsingAjax() verpackt;

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

Innen uploadFilesUsingAjax(),

schrieb ich meinen Code auf diese Weise

function uploadFilesUsingAjax() { 
    var files = pages; // pages is a global variable which is an array of files 
    var url = "https://stackoverflow.com/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 habe ich nicht in der Lage war, eine Menge von Dateien zu laden, bevor ich zum Erfolg Seite umgeleitet wurde.

Ich habe verschiedene StackOverflow-Lösungen ausprobiert, wie man das macht. Bis jetzt funktioniert nichts. Bitte beraten.

Einige Codes wurden abgeschnitten, um Platz zu sparen.

Antwort

2

Alle Ihre Versprechen sind parallel und nicht sequentiell.

Eine Zusage stellt einen bereits ausgeführten Task dar. Versprechen in JavaScript, im Gegensatz zu C# -Tasks oder anderen Abstraktionen, sind bereits gestartet. Die Art, eine Aufgabe darzustellen, die nicht gestartet wurde, ist eine Funktion, die ein Versprechen zurückgibt.

Seit promises[i] ist schon ein Versprechen - wenn Sie promise.then(object) tun, fügt es nicht einen .then Handler aber eher sofort zurück. .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. Sie brauchen auch nicht die .when. Erstellen Sie eine Funktion, die ein Upload-Prozess als solche 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 
    } 
} 

nun die Dateien Aufgaben zuordnen können:

var tasks = files.map(createUploadTask); 

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

Nun können Sie diese Kette:

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 jetzt auch nicht, wann verwenden müssen, da Sie eine einzelne Versprechen zurück. Ich nehme an, dass Sie das tatsächliche Ergebnis hier nicht benötigen (aber nur Erfolg/Misserfolg wissen).

Sie einfach tun:

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; 
} 
+0

ich habe ein kleines Problem mit der '.map', weil die URL unterschiedlich sein können, je nachdem, was ich will die uploadFilesUsingAjax() verwenden. Wie überwinde ich diese Situation? –

+0

Sie ordnen ein Array von _stuff_ einem Array von Anforderungsaufgaben zu. Sie haben Zugriff auf das Dateiobjekt - Sie können '.map' auf eine andere URL basierend auf einer Eigenschaft des' file' Objekts, die an die Funktion, die Sie '.map' übergeben, übergeben. –

+0

Entschuldigung für den früheren Kommentar. Ich weiß, wie ich das Problem umgehen kann. Ich habe stattdessen Alias-Funktionen geschrieben. Ich habe versucht, eine zusätzliche Klammer hinzuzufügen, die Sie in Ihrer Antwort fehlten. BUt konnte nicht, weil der StackOverflow verlangt, dass ich mindestens 6 Zeichen hinzufüge. Sie fehlen im 'd.reject (new Error (" Uploadfiles mit keine Dateien zum Hochladen "));' Sollte am Ende doppelte Klammern sein. –

Verwandte Themen