在 while 循环中延迟

Deferred in a while loop

所以我想在 jquery 中执行延迟的 ajax 请求,直到我收到特定的服务器响应(非空)。我该怎么做?

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

你不能在 Javascript 中这样循环。 Javascript 是一个事件驱动的系统。当您像这样循环时,将无法处理任何其他事件。因此,即使是您的第一个 Ajax 呼叫也不会得到处理。事实上,当客户端试图同时进行数百万次 ajax 调用时,您可能会用 运行 一些资源将 JS 引擎推入地下。

相反,您可以异步使用 ajax 结果,然后根据结果决定是否再次调用它:

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();

如果你想让整个事情成为return一个承诺,你可以这样做:

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。尽可能快地不断轮询某些服务器几乎从来都不是正确的事情。如果您只有几个用户,这可能会很好地工作,但是一旦您有很多用户,所有要做的就是用空轮询请求淹没您的服务器,而在大多数情况下,没有什么可以 return客户端。这是处理负载的噩梦。最好找一个不轮询的架构,但如果你要轮询,那么至少使用某种定时器在未来某个时间轮询而不是尽可能快。

P.P.S。如果你真的只是在等待服务器上的一些值发生变化,那么也许你应该使用 webSocket 连接。这样,客户端就建立了与服务器的连接并且连接持续存在,然后在将来的任何时候,服务器都可以简单地向客户端发送消息。客户端根本不需要轮询。这可以大大提高您的服务器基础架构的效率,并可以提供更及时的结果。

要给予更大的控制权,写doUntilResult()接受:

  • 一个doThis回调函数,它确定要做什么,以及re-try/terminate条件。
  • 一个整数,决定调用之间的延迟。
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();
}

现在,您有了一个通用的 doUntilResult() 函数,可以改变您对 "done until" 的想法而无需重新编写。一切都在调用(或调用)中指定。

原题调用如下:

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

编辑后的问题,调用如下:

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

无论您想做什么,始终确保回调的 .then 链终止于 returns null 每当轮询要继续的函数中。

Here's a simple demo 生成一个0-10的随机数; 9 或更大的数字被视为数据;低于 9 将导致重试。 (在控制台中监控进度)。