Deferred in a while loop

六月ゝ 毕业季﹏ 提交于 2019-12-12 18:17:14

问题


So I want to do a deferred ajax request in jquery until I receive a specific server response (non-null). How would I go about doing that?

while (data.response != null) {
  $.ajax(..).done(function(data);
}

function doUntilResult() {
    Server.doA().done(function(data) {
      Server.doB(data).done(function(result) {
          //if result == null, repeat again
      });
    });
}

回答1:


To give a large measure of control, write doUntilResult() to accept :

  • a doThis callback function, which determines what is to be done, and the re-try/terminate condition.
  • an integer, which determines the delay between calls.
function doUntilResult(doThis, t) {
    function delay() {
        return $.Deferred(function(dfrd) {
            window.setTimeout(dfrd.resolve, t);
        });
    }
    function poll() {
        return $.when(doThis()).then(function(data) { // $.when() caters for non-async functions to be passed.
            return (data === null) ? delay().then(poll) : data; // continue on null, otherwise return data.
        });
    }
    return poll();
}

Now, you have a generalised doUntilResult() function, making it possible to change your mind about what is to be "done until" without re-writing. Everything is specified in the call (or calls).

For the original question, call as follows :

doUntilResult(function() {
    return $.ajax(..).then(function(data) {
        return data || null; // adjust as required to ensure that `null` is returned only for the "continue" condition.
    });
}, 1000); // 1 second delay between calls

For the edited question, call as follows :

doUntilResult(function() {
    return Server.doA().then(function(data) {
        return Server.doB(data);
    }).then(function(result) {
        return result || null; // adjust as required ...
    });
}, 1000); // 1 second delay between calls

Whatever you want to do, always ensure that the callback's .then chain terminates in a function that returns null whenever the poll is to continue.

Here's a simple demo which generates a random number from 0-10; numbers of 9 or greater are treated as data; under 9 will cause a re-try. (Monitor progress in console).




回答2:


You can't loop like this in Javascript. Javascript is an event-driven system. When you are looping like this, no other events can ever get processed. As such, not even your first Ajax call will get processed. In fact, you will probably just drive the JS engine into the ground by running out of some resource as the client tries to make millions of ajax calls all at once.

Instead, you can use the ajax result asynchronously and then decide from the result whether to call it again:

function poll() {
    $.ajax(...).then(function(data) {
        if (!data.xxxx) {
            // call it again after some short delay
            setTimeout(poll, 1000);
        } else {
            // got the result we wanted, process it
        }
    })
}

// start the polling
poll();

If you want the whole thing to return a promise, you can do this:

function delay(t) {
    return new $.Deferred(function(def) {
        setTimeout(def.resolve, t);
    }).promise();
}

function poll() {
    return $.ajax(...).then(function(data) {
        if (!data.xxxx) {
            // call it again after some short delay
            return delay(1000).then(poll);
        } else {
            // got the result we wanted, process it
            return someValue;
        }
    })
}

// start the polling
poll().then(function(result) {
    // process result here
});

P.S. It is pretty much never the right thing to just constantly poll some server as fast as you possibly can. This might work fine if you only have a couple of users, but as soon as you have lots of users, all that will do is overwhelm your server with empty polling requests where most of the time, there's nothing to return to the client. This is nightmare for handling load. It's even better to find an architecture that is not polling, but if you are going to poll, then at least use some sort of timer to poll at some future time rather than as fast as possible.

P.P.S. If you're really just waiting for some value to change on the server, then perhaps you should use a webSocket connection. With that, the client establishes the connection to the server and the connection persists and then at any point in the future, the server can simply send a message to the client. The client doesn't have to poll at all. This can be massively more efficient on your server infrastructure and can deliver more timely results.



来源:https://stackoverflow.com/questions/38546932/deferred-in-a-while-loop

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