2011-02-08 92 views
4

我在表單中使用了Plupload file uploader。我想定製它,以便當表單被提交時,即點擊「提交」按鈕時,發生的第一件事是文件上傳,然後提交表單。如何使用jQuery.Deferred對象來等待異步函數調用完成?

從我所知道的情況來看,我可能對此有錯,但看起來uploader.start()是一個異步函數調用。所以目前,上傳將開始,表單將在文件上傳之前提交。問題是我無法控制這個函數調用。

我最近閱讀了關於new release of jQuery 1.5和新的Deferred Object,它似乎有可能幫助我解決這個問題。是否有辦法等待異步函數調用完成其工作,然後在調用後繼續執行代碼。所以我在尋找類似下面的僞代碼...

var uploader = $('#plupload_container').pluploadQueue(); 

$('#submitButton').click(function() { 

    // if there are files to be uploaded, do it 
    if (uploader.files.length > 0) { 

     // make the call and wait for the uploader to finish 
     uploader.start(); 
     while (the uploading is not done) { 
     wait for the uploader to finish 
     } 

     // continue with submission 
    } 
}); 

有沒有辦法爲「等待」 uploader.start()完成,基本上是把一個暫停的單擊事件處理程序,使所有的文件可以先上傳,然後點擊事件處理程序的其餘部分可以完成執行?我試過以下,但完成文件上傳前「完成」印...

$.when(uploader.start()).then(function() { 
    console.log("done") 
}); 

另一個有價值的信息片......我的某些事件綁定到這個uploader對象實例,如「 UploadProgress「或」UploadComplete「。例如,我可以在發生「UploadComplete」事件時以某種方式使用延遲對象來捕獲事件嗎?有沒有AJAX-y的方式來做到這一點?

謝謝。

回答

5

你的問題是,雖然uploader.start做代碼異步的工作,uploader.start必須返回一個jquery $.deferred對象。

從您上傳插件的最新源:

/** 
* Starts uploading the queued files. 
* 
* @method start 
*/ 
start : function() { 
    if (this.state != plupload.STARTED) { 
     this.state = plupload.STARTED; 
     this.trigger("StateChanged"); 
     uploadNext.call(this); 
    } 
}, 

所以它不返回延期對象。相反,在uploadNext功能有這行代碼:

this.trigger("UploadComplete", files);

所以我們只需綁定到你的上傳,

uploader.bind("UploadComplete", function(files) { 
    // your code 
}); 

我從來沒有使用的插件,但這個should工作。祝你好運。

如果你必須使用deferreds那麼你可以隨時像這樣的僞代碼:

var uploader = $('#plupload_container').pluploadQueue(); 
var def = $.Deferred(); 
uploader.bind("UploadComplete", function(files) { 
    def.resolve(files); 
}); 
$('#submitButton').click(function() { 
    if (uploader.files.length > 0) { 
     uploader.start(); 

     def.done(function(files) { 
      def = $.Deferred(); // reset the deferred object. 
      // rest of your click handler. 
     }); 

    } 
}); 
+0

@Raynos ...謝謝你的回覆。這一切看起來不錯,我甚至沒有想過改變源代碼,但這是一個好主意!當我回到辦公室時,我會試試這個,讓你知道會發生什麼。 – Hristo 2011-02-09 23:53:21

-1

是的。在ajax api中,jquery新推遲的一點是允許您的代碼等待其他異步代碼。

如果您有多個互相依賴的異步調用,則延遲將允許您在完成所有操作後執行一些操作。同樣的想法適用於此。

+2

心靈呈現出一些代碼? – Hristo 2011-02-08 16:00:10

3

在一個假想的上傳會話的上下文:

var files = ["file1.txt", "file2.txt", "file3.txt"]; 

這些都是我們想上傳的文件。讓我們來裝配具有每次上傳延期對象的另一個數組:)與這一類遞延對象

var uploads = files.map(upload_one); 

我們調用$。當(我們還規定每次上傳後做什麼,什麼時候出現任何故障,而當一切完全完成:

$.when(uploads) 
    .progress(function() { 
    // report to user, step progress bar, etc 
    }) 
    .fail(function() { 
    // display error 
    }) 
    .done(function() { 
    // all uploads finished, do stuff 
    }); 

這是每個單獨上傳的工作函數。它返回推遲對象,並根據各自的上傳也稱成功或錯誤的功能:

function upload_one(file) { 
    var deferred = new $.Deferred(); 
    // start upload 

    // if finished: 
    deferred.notify(); 
    deferred.resolve(); 

    // if failed: 
    deferred.reject(); 

    return deferred; 
}