2014-04-14 13 views
5

我打算使用jQuery上傳一組文件。如何在一個函數中順序發送文件上傳,這也是一個延期承諾?

這個意圖被包裹在一個叫做uploadFilesUsingAjax()的函數中;

var uploadFilesPromise = uploadFilesUsingAjax(); 

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

我需要等待所有的文件成功上傳,然後再做其他事情。

裏面uploadFilesUsingAjax()

我寫我的代碼,這樣

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

不幸的是,我沒能上傳大量的文件之前,我得到重定向到成功頁面。

我已經嘗試過關於如何做到這一點的各種StackOverflow解決方案。到目前爲止沒有任何工作請指教。

某些代碼已被截斷以節省空間。

回答

2

所有的承諾是平行的,而不是順序的。

承諾代表已經運行任務。 JavaScript中的承諾,不像C#任務或其他抽象已經開始。表示尚未開始的任務的方式是返回承諾的函數。

既然promises[i]已經是承諾 - 當你做promise.then(object)它不會添加.then處理程序,而是立即返回。 .then忽略任何不是函數的參數。

這就是爲什麼它返回的時間早,它會在第一個承諾完成時立即返回。您也不需要.when。創建創建一個上傳過程作爲這樣的功能:

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

現在,你可以將文件映射到任務:

var tasks = files.map(createUploadTask); 

注意,現在的任務是每個功能返回一個承諾通過文件上傳。他們不是承諾。現在

,你可以把它們連:

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; 

您現在還不必因爲你返回承諾時使用。我假設你不需要這裏的實際結果(但只知道成功/失敗)。

你根本:

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

我必須使用'.map'一個小問題,因爲URL可能取決於我想使用uploadFilesUsingAjax()是不同的。我如何克服這種情況? –

+0

您正在將_stuff_數組映射到請求任務數組。您可以訪問文件對象 - 根據傳遞給''.map'函數的'file'對象的屬性,您可以將'.map'轉換爲不同的URL。 –

+0

對此感到抱歉。我知道如何解決這個問題。我改寫了別名函數。我曾嘗試在答案中添加一個額外的括號。 BUt不能,因爲StackOverflow要求添加至少6個字符。你錯過了'd.reject(新錯誤(「被調用的uploadFiles沒有要上傳的文件」));'最後應該是雙括號。 –

相關問題