在 while 循环中延迟
Posted
技术标签:
【中文标题】在 while 循环中延迟【英文标题】:Deferred in a while loop 【发布时间】:2016-07-23 22:25:32 【问题描述】:所以我想在 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
);
);
【问题讨论】:
【参考方案1】:你不能在 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();
如果你想让整个事情都返回一个承诺,你可以这样做:
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.P.S.如果您真的只是在等待服务器上的某些值发生变化,那么也许您应该使用 webSocket 连接。这样,客户端建立与服务器的连接并且连接持续存在,然后在未来的任何时候,服务器都可以简单地向客户端发送消息。客户端根本不需要轮询。这可以大大提高您的服务器基础架构的效率,并且可以提供更及时的结果。
【讨论】:
我想在这次投票中使用延期,这可能吗?这样我就可以做 poll().done(...) 当然只会在 !data.xxx 时调用? @Wesley - 我不明白你想要什么。我的答案中有$.ajax(...).then()
,它已经使用了一个承诺。我更喜欢使用 ES6 标准 .then()
而不是 jQuery 特定的 .done()
。如果您希望在轮询完成后整个事情都返回一个承诺,那可以做到(尽管这不是您在问题中要求的)。
@Wesley - 我又添加了一个选项。
也不明白,你在回调中使用了return,那是怎么回事?我只使用 .done ,你总是必须用返回值来解决或拒绝。
最后一个问题,我上面的代码不是很详细,我基本上在那个“循环”中做了两个请求,见编辑过的代码;那么它将如何工作,因为我正在处理多个延期。【参考方案2】:
要进行大量控制,请写doUntilResult()
接受:
doThis
回调函数,用于确定要执行的操作以及重试/终止条件。
一个整数,用于确定调用之间的延迟。
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()
函数,可以在不重写的情况下改变您对“完成直到”的事情的想法。一切都在调用(或调用)中指定。
对于原始问题,请按以下方式调用:
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 链终止于一个函数,该函数在轮询继续时返回 null
。
Here's a simple demo 生成一个 0-10 的随机数; 9 或更大的数字被视为数据;低于 9 会导致重试。 (在控制台中监控进度)。
【讨论】:
以上是关于在 while 循环中延迟的主要内容,如果未能解决你的问题,请参考以下文章