繁体   English   中英

while循环中的异步函数

[英]Asynchronous function in a while-loop

我有一个问题,关于如何在while循环中执行异步任务,直到满足某些条件。 这更像是一个理论问题,但我可以看到在某些情况下这可能是一个问题。

我将尝试在一个示例中演示该问题(我在这里使用JavaScript,但您可以使用任何语言):

我可以有一个设备,我想保留我的应用程序,直到该设备达到特定状态。 如果我可以使用设备状态进行getrieve的方法是同步,则代码可能如下所示:

// Hold until the desired state is reached
var state = false;
while (!state) {
    state = device.getStateSync();
}
// [...] continue the program

我现在的问题是:当我从设备获得的是异步getState函数时,如何转换此代码? 无论调用的执行时间有多长,代码都应该工作,并且应该记住我正在处理有限的内存和堆栈大小。

// [...] This would call the async function in a loop and crash the program
while (!state) {
    // [...] something
    device.getStateAsync(function(newState) {
        state = newState;
    });
    // [...] something else
}

我找到的这篇文章有一个递归解决方案( http://blog.victorquinn.com/javascript-promise-while-loop )。 虽然这是一个很好的解决方案,但在某些时候,如果过于频繁地调用循环,它将遇到堆栈大小的问题。

现在我有直觉,可能没有解决方案。 你知道有什么办法吗? 或者你知道如何证明没有办法吗? 随意包含更复杂的概念,如线程,承诺或期货。

请记住,这是一个理论问题,例子是我无法改变我正在使用的框架(或设备)的情况。

感谢您的每一个回应和想法!

佩德罗

在javascript中,除非实际更改条件的代码位于循环内部或循环中调用的某个函数的副作用,否则无法循环等待条件更改。 那是因为javascript是单线程的(除了这里没有考虑的webworkers),只要循环在javascript中循环,没有其他代码可以运行,所以没有其他代码可以改变你的条件变量。 当循环等待永远不会改变的东西时,你将只有一个无限循环。 最终,浏览器会抱怨您运行无响应的代码并将其关闭。

因此,javascript中没有不确定或长的等待循环。 可以循环一秒左右只是让一些时间过去,但这很少有用,有效或者是编写JS代码的最佳方法。

相反,您必须在条件更改时触发事件或回调,并且感兴趣的代码可以订阅该事件或注册其回调。 或者,您必须轮询计时器以查看条件已更改(第一个选项是首选选项)。


如果您正在设计一个API,您希望能够允许某些调用代码知道状态何时发生更改,通常您将实现回调或承诺。 回调方法可能如下所示:

device.registerStateChangeCallback("type of state interested in", fn);

然后,只要指定的状态更改为新值,API就会调用传入的回调函数。 这取决于API是一次性通知,还是每次状态发生变化时都会发生,直到取消注册回调为止。

因此,调用程序不会让调用者在繁忙的循环中等待状态更改,而是调用异步代码(这就是javascript如何适用于这种类型的东西),并在稍后状态更改时调用回调。 例如,调用者的代码可能如下所示:

device.registerStateChangeCallback("syncState", function(newState) {
     // caller puts code here that wants to do something when 
     // the syncState has changed
});

如果通知只是一次性,那么您也可以使用promises,API只返回一个在syncState更改时解析的promise:

device.registerStateChange("syncState").then(function(newState) {
     // caller puts code here that wants to do something when 
     // the syncState has changed
});

承诺的缺点是它们纯粹是单一用途(仅一个通知),所以如果你想要多个通知,那么最好使用回调。 承诺优于回调的优势在于它们提供了许多功能,可以将它们与其他事件同步(例如排序,等待一系列事件全部完成,协调多个异步事件等等)并且它们提供更好的异步错误处理。

你不能这样做。 原因是Javascript是单线程的。 while循环正在运行时,没有其他任何东西运行,因此无论预期更新任何异步任务,设备状态都将永远无法运行。 Javascript中的异步任务由主事件处理程序循环运行。 这意味着在您从脚本返回到事件处理程序之前,异步操作将不会运行,或者脚本会对事件处理程序执行调用(这仅在脚本通过confirmprompt等待用户输入时才会发生)。

这确实是一个非常理论化的问题。 拥有一个异步API来获取当前状态会很奇怪。 你很可能会有:

  • 一种同步方法,可以为您提供当前状态;
  • 或者是一种异步方法,可以在状态发生变化时回复您。 在这种情况下,无需循环,只需等待回调即可。

但是,如果你确实有这样一个API的具体例子,请告诉我们......

此函数使用setTimeout,因此回调返回而不递归。 要求是您的环境实现了setTimeout机制,因为这不是JavaScript的一部分。

var callback = function callback(result){
   if(result == "some condition"){
       //done
   } else {
       setTimeout(device.getStateAsync(callback), 10);
   }
}

device.getStateAsync(callback);

我知道这是迟到的,但es6提供了一个更好的方法来做到这一点。 解决方案在于使用Generators + Promises

看看这个我必须创建Twitter线程的存储库,其中前面的推文必须回复之前和使用,这是通过获取当前推文的ID并使用它来发布下一条推文来完成的。

看这里=> https://github.com/Udokah/tweet-threader

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM