强制jQuery Deferred等待Ajax在“”中完成;那么“;处理程序

Force jQuery Deferred to wait until Ajax complete in "then" handler

本文关键字:那么 程序 处理 Deferred jQuery 等待 Ajax 强制      更新时间:2023-09-26

我有这样的情况,我认为我需要创建一个带有"then"处理程序的Deferred对象,但要等到"then"处理程序完成了自己的承诺后才能继续。

用例是一个记录对象,上面的函数是它的保存方法。记录对象有一个名为saveQueue的属性,该属性设置为$。对记录的实例化执行Deferred()。对saveQueue的解析调用应该确保Deferred总是尽快执行附加到它的每个新处理程序。其想法是,您可以在短时间内连续多次调用记录中的save,但这些调用将一个接一个地运行,而不会重叠。

我正在使用Deferred来对Ajax调用进行排队,这样直到上一个调用完成后才运行。然而,通过相同的方法,我想返回一个可以由jQueryAjax对象解析/拒绝的Deferred,如下所示:

 record.saveQueue = $.Deferred();
 self.save = function( record ){
    var deferredAction = $.Deferred();
    deferredAction.then(function() {
        return $.post("/example_save_endpoint");
    });
    record.saveQueue.always(function(){
      deferredAction.resolve();
    }).resolve();
    return deferredAction;
  }

然而,当我使用此代码时,deferredAction承诺总是以resolved结束,可能是因为#then处理程序返回了一个"挂起"(因此是不拒绝)承诺。是否有任何方法可以强制Deferred等待Ajax承诺完成后再解决/拒绝?或者还有其他更好的穿针方法吗?

你的想法可能可行,但

  • 不能每次调用方法时都使用.resolve()来解析队列,而是应该仅使用已解析的promise来初始化队列
  • 要在record.saveQueue上实际队列,需要在每次方法调用时对其进行更改(覆盖),以表示最新请求的结束

我们不需要任何延迟,因为我们可以处理$.post返回的承诺。

所以使用这个:

var emptyQueue = $.when(undefined); // an already fulfilled promise as the start
// equivalent: = $.Deferred().resolve().promise();
function startQueue() {
    return emptyQueue; // yes, this delibaretely returns a constant, the begin
                       // of the queue always looks the same (and is never mutated)
}
// every time you create a record, do
record.saveQueue = startQueue();
// and use that in your methods:
this.save = function(record) {
    var queuedRequestResult = record.saveQueue.then(function() {
        return $.post("/example_save_endpoint");
//      ^^^^^^ promises chain :-)
    });
    // Magic happens here:
    record.saveQueue = queuedRequestResult // we swap the previous queue promise for a new
                                           // one that resolves only after the request
      .then(startQueue, startQueue);       // and make sure it then starts with a fresh
                                           // queue, especially when the request failed
    //.then(null, startQueue) is similar, except unnecessarily remembering the last result
    return queuedRequestResult;
}

我可能会选择不这样做,但延迟/承诺确实可以用作排队设备。

你需要对你已经尝试过的东西稍作改动。

self.queue = $.when();//A resolved promise, used to form a queue of functions in a .then() chain.
self.save = function(data) {
    var dfrd = $.Deferred();//A Deferred dedicated to this particular save.
    self.queue = self.queue.then(function() {
        return $.post("/example_save_endpoint", data) //Make the AJAX call, and return a jqXHR to ensure the downstream queue waits for this jqXHR to resolve/reject.
            .then(dfrd.resolve, dfrd.reject) //Resolve/reject the Deferred for the caller's benefit
            .then(null, function() {
                //Force failure down the success path to ensure the queue is not killed by an AJAX failure.
                return $.when();//Return a resolved promsie, for the queue's benefit.
            });
    });
    return dfrd.promise();//allow the caller to do something when the AJAX eventually responds
}

有关解释,请参阅代码中的注释