Am trying to create a custom asynchronous function asyncFunc in Nodejs that behaves like built in asynchronous JavaScript functions such as setTimeout. However, the function behaves like a synchronous function.
function asyncFunc(i, n){
return new Promise(function(resolve, reject){
// while loop to simulate a long running task
while (i < n){
r = n % i
i = i + 1
}
resolve('success data')
})
}
asyncFunc(1, 1000000000)
.then((data)=> {
console.log(data);
})
// 'test' should be logged to the console immediately on run of script
console.log('test');
I expected the line of code console.log(‘test’) just below the call to asyncFunc to execute immediately and log ‘test’ to the console instead ‘test’ gets logged to the console after about 5 seconds followed by ‘success data’ from asyncFunc.
Is there something am missing about asynchronous functions in JS?
2
Answers
JavaScript behaves as if it were single-threaded: it uses an event loop to handle asynchronous actions. Furthermore, the function that you pass into a Promise ("executor") is called synchronously. Consequently, when you call your
asyncFunc
, it doesn’t return until it has already traversed your entire loop.This makes it difficult to emulate functions like
setTimeout
orsetInterval
, particularly using "busy waiting" where you perform a useless action (like your loop here) until a given amount of time has passed. Even if you could wait the appropriate amount of time, the browser or server process would not be able to get anything done between the start and end of the loop; you would need to return control to the event loop so it could handle other interactions.There are some caveats to this description: Features like service workers can perform synchronous actions independent of the owning thread. Furthermore, there are ways of deferring to a Promise that allow for other Promise resolutions to run ("microtask queue") but might not make room for other types of interactions ("task queue" or "macrotask queue"). As such, the simple explanation is that
setTimeout
andsetInterval
are effectively impossible to emulate in JavaScript without effectively creating your own event loop.What is happening is that when you call
asyncFunc
, the function passed to thenew Promise
constructor runs immediately. Then, it resolves, and the result and the invocation of.then
is queued up in the microtask queue.Then, the main code continues and calls
console.log('test')
. When that code block exits, Javascript looks for the next microtask to execute, and invokes the function passed to.then()
.Javascript is single-threaded, and things only happen concurrently if you’re making an API call which the Javascript engine runs in the background (such as fetching the contents of a URL, or using setTimeout).