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

蹲街弑〆低调 提交于 2019-12-02 07:51:27
Bergi

Your idea might work, but

  • the queue must not be resolved using .resolve() every time the method is called, instead it should be initialised only with a resolved promise.
  • to actually queue on the record.saveQueue, it needs to be changed (overwritten) on every method call, to represent the end of the latest request.

And we don't need any deferreds for that, as we can work with the promises that $.post returns.

So use this:

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

I would probably choose not to do it this way, but a deferred/promise can indeed be used as a queuing device.

You need a slight(?) variation of what you already tried.

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
}

For explanation, see comments in code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!