While循环中的异步功能 [英] Asynchronous function in a while-loop

查看:580
本文介绍了While循环中的异步功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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



我可以拥有一个设备,并且我想保留我的应用程序,直到该设备达到特定状态为止。如果我可以获取设备状态的方法是同步的,则代码可能如下所示:

  //保持直到达到所需状态
var state = false;
while(!state){
state = device.getStateSync();
}
// [...]继续执行程序

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

  // [...]这将在循环中调用异步函数并使程序
崩溃,而(!state){
// // ...]东西
device.getStateAsync(function(newState){
state = newState;
});
// [...]其他
}

此帖子我发现有一个递归解决方案( http://blog.victorquinn.com/javascript-promise -while-循环)。虽然这是一个不错的解决方案,但如果调用该循环的次数过多,有时会遇到堆栈大小的问题。



现在我有一种直觉可能没有解决方案。你知道有什么办法吗?还是您知道如何证明没有办法做到这一点?可以随意包含诸如线程,承诺或期货之类的更复杂的概念。



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



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



Pedro

解决方案

在javascript中,除非实际更改条件的代码位于内部,否则您无法循环等待条件更改该循环或循环中某些函数的副作用。这是因为javascript是单线程的(此处未考虑的webworkers除外),因此只要在javascript中循环,就无法运行其他代码,因此没有其他代码可以更改条件变量。您将简单地拥有一个无限循环,因为循环等待着永不改变的事物。最终,浏览器会抱怨您正在运行无响应的代码,然后将其关闭。



因此,javascript中没有不确定的或长时间的等待循环。可能会花一秒钟左右的时间来循环一段时间,但这很少是有用的,高效的或编写JS代码的最佳方法。



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






<如果在设计API时希望能够允许某些调用代码知道状态何时发生变化,那么通常可以实现回调或promise。回调方法如下所示:

  device.registerStateChangeCallback(感兴趣的状态类型,fn); 

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



因此,而不是让调用者等待繁忙的循环,直到状态发生变化,调用方将编写一个异步代码(这是javascript处理此类内容的方式),并带有一个回调,该回调将在状态变化后的某个时候被调用。例如,调用者的代码可能如下所示:

  device.registerStateChangeCallback( syncState,function(newState){
//调用者将代码放在此处,当
// syncState更改了
}时,该代码想要执行某些操作






如果通知仅是一次,那么您也可以使用Promise,并且当syncState更改时,API仅返回一个已解决的Promise:

  device.registerStateChange(  [syncState)。then(function(newState){
//调用者在此处放置了想要在
// syncState更改
}时执行某操作的代码)

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


I have a question about how to perform an asynchronous task in a while-loop until some condition is met. This is more of a theoretical question but I can see how this could be an issue in some scenarios.

I'll try demonstrate the problem at an example (I'm using JavaScript here, but you can use any language):

I could have a device and I want to hold my application until that device has reached a specific state. If the method with which I can getrieve with state of the device is synchronouse, the code could look like this:

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

My question now is: How can I transform this code when all I get from the device is a asynchronous getState function? The code should work no matter how long the execution time of the call is and should keep in mind that I'm working on limited memory and stack size.

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

This one post that I found has a recursive solution (http://blog.victorquinn.com/javascript-promise-while-loop). While this is a nice solution, at some point it will run into stack-size problems, if the loop is called too often.

Right now I have the gut feeling that there might be no solution. Do you know of any way to do this? Or do you know how to prove that there is no way to do it? Feel free to include more complex concepts like Threads, Promises or Futures.

Please bear in mind, that this is a theoretical question and the example is for a situation where I have no way of changing the framework (or device) I am working with.

Thanks for every response and idea!

Pedro

解决方案

In javascript, you cannot loop waiting for a condition to change unless the code that actually changes the condition is inside that very loop or a side effect of some function called in the loop. That's because javascript is single threaded (except for webworkers which aren't being considered here) so as long as a loop is looping in javascript, no other code can run so no other code can ever change your condition variable. You will simply have an infinite loop as the loop waits for something that can never change. Eventually the browser will complain that you have unresponsive code running and shut it down.

Because of that, there aren't indeterminate or long wait loops in javascript. It is possible to loop for a second or so just to let some time pass, but that's rarely useful, productive or the best way to write JS code.

Instead, you have to either trigger an event or callback when the condition changes and the interested code can subscribe to that event or register its callback. Or, you have to poll on a timer to see what the condition has changed (the first option is the preferred choice).


If you were designing an API where you wanted to be able to allow some calling code to know when a state changes, usually you would implement either a callback or a promise. The callback approach could look like this:

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

Then, the API will call the passed in callback function whenever the specified state changes to a new value. It's up to the API whether this is a one-time notification or whether it happens every time the state changes until the callback is deregistered.

So, rather than having the caller wait in a busy loop until the state changes, the caller writes async code (this is how javascript works for this kind of stuff) with a callback that will be called sometime later when the state changes. For example, a caller's code might look like this:

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


If the notifications are meant to be one time only, then you could also use promises and the API simply returns a promise that is resolved when the syncState changes:

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

The disadvantages of promises are that they are purely single use (one notification only) so if you want multiple notifications, then better to use callbacks. The advantages of promises over callbacks is that they provide a lot of features for synchronizing them with other events (such as sequencing, waiting for a series of events to all finish, coordinating multiple async things, etc...) and they provide better async error handling.

这篇关于While循环中的异步功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆