簡體   English   中英

強制jQuery Deferred等待Ajax在“ then”處理程序中完成

[英]Force jQuery Deferred to wait until Ajax complete in “then” handler

在某些情況下,我認為我需要使用“ then”處理程序創建一個Deferred對象,但是要等到“ then”處理程序完成其自己的承諾后,再繼續。

用例是一個記錄對象,上面的功能是它的save方法。 記錄對象具有名為saveQueue的屬性,該屬性在記錄的實例化時設置為$ .Deferred()。 應該對saveQueue進行resolve調用,以確保那里的Deferred總是盡可能快地執行附加到它的每個新處理程序。 您可以在短時間內連續多次保存記錄,但這些調用會一次又一次地運行,並且不會重疊。

我正在使用Deferred來排隊Ajax調用,以便直到上一個調用完成后才能運行。 但是,從同一個方法中,我想返回一個可以由jQuery Ajax對象解析/拒絕的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處理程序返回的是“待處理”(因此是非拒絕)承諾。 是否有任何方法可以迫使延遲者在解決/拒絕之前等待Ajax承諾完成? 還是有另一種更好的方法來穿針?

我可能會選擇不這樣做,但是延遲/承諾確實可以用作排隊設備。

您需要對已經嘗試的內容進行細微的變化?

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
}

有關說明,請參見代碼中的注釋

您的想法可能有效,但是

  • 不能在每次調用該方法時都使用.resolve()來解決隊列,而只能使用已解決的諾言來初始化該隊列。
  • 以便實際上在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;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM