Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous function in a while-loop

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

like image 475
torpedro Avatar asked Aug 15 '14 22:08

torpedro


People also ask

Is while loop asynchronous?

This API method is asynchronous and it's in a while loop. If it returns an empty array, the while loop finishes. Otherwise, it loops.

What is asynchronous function?

An asynchronous function is any function that delivers its result asynchronously – for example, a callback-based function or a Promise-based function. An async function is defined via special syntax, involving the keywords async and await . It is also called async/await due to these two keywords.

Can a for loop be async?

For loops. Combining async with a for (or a for...of ) loop is possibly the most straightforward option when performing asynchronous operations over array elements. Using await inside a for loop will cause the code to stop and wait for the asynchronous operation to complete before continuing.

Can we await async function?

The await operator is used to wait for a Promise and get its fulfillment value. It can only be used inside an async function or a JavaScript module.


2 Answers

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.

like image 106
jfriend00 Avatar answered Sep 16 '22 22:09

jfriend00


You can't do this. The reason is that Javascript is single-threaded. While the while loop is running, nothing else runs, so whatever asynchronous task is expected to update the device state will never get a chance to run. Asynchronous tasks in Javascript are run by the main event handler loop. This means that asynch operations won't run until you return from your script back to the event handler, or the script performs a call into the event handler (this only happens when the script waits for user input with confirm or prompt).

like image 40
Barmar Avatar answered Sep 16 '22 22:09

Barmar