我如何使用jQuery.Deferred对象等待异步函数调用完成?

时间:2011-02-08 15:13:57

标签: jquery ajax plupload jquery-deferred

我在表单中使用Plupload file uploader。我想自定义它,以便在提交表单时,即单击“提交”按钮时,首先发生的是文件上传,然后是提交表单。

据我所知,我可能错了,但似乎调用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()完成,实际上是在click事件处理程序上暂停,这样所有文件都可以先上传,然后其余的click事件处理程序就可以完成了执行?我尝试了以下内容,但在文件上传完成之前打印了“完成”...

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

另一个有用的信息...我可以将某些事件绑定到此uploader对象实例,例如“UploadProgress”或“UploadComplete”。例如,我可以以某种方式使用延迟对象来捕获“UploadComplete”事件触发的时间吗?是否有AJAX-y方法可以做到这一点?

感谢。

3 个答案:

答案 0 :(得分: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有效。祝你好运。

如果你必须使用延迟,那么你总是可以使用像这样的伪代码:

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.
      });

   }
});

答案 1 :(得分:3)

在假想的上传会话中:

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

这些是我们要上传的文件。让我们组装另一个数组,每个上传都有一个延迟对象:

var uploads = files.map(upload_one);

我们用这个延迟对象数组调用$ .when(),我们还指定每次上传后要做什么,什么时候失败以及什么都完全完成:

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

这是每个单独上传的工作功能。它返回 deferred 对象,并调用成功或错误函数以响应单个上传:

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

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

  // if failed:
  deferred.reject();

  return deferred;
}

答案 2 :(得分:-1)

是。在ajax api中jquery的新延迟点是允许你的代码等待其他异步代码。

如果您有多个相互依赖的异步调用,则延迟将允许您在完成后执行某些操作。同样的想法适用于此。