I have a question to async, await and setTimeout(). I thought, I use asynchron functions for slow processes. So I tried it with a large loop. On my Computer, it needs few seconds to run the following code:
function slowFunction() {
return new Promise(resolve => {
setTimeout(() => {
for (let i = 0; i < 4000000000; i++) {};
resolve('Ready at ' + new Date().toLocaleTimeString('de'));
}, 0);
});
};
console.log('Start: ' + new Date().toLocaleTimeString('de'));
(async () => {
console.log('Call slow function.');
console.log(await slowFunction());
})();
console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));
The output is:
Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:20
Ready at 16:39:23
And now the question: What is the difference to the next code:
function slowFunction() {
return new Promise(resolve => {
for (let i = 0; i < 4000000000; i++) {};
resolve('Ready at ' + new Date().toLocaleTimeString('de'));
});
};
console.log('Start: ' + new Date().toLocaleTimeString('de'));
(async () => {
console.log('Call slow function.');
console.log(await slowFunction());
})();
console.log('There is no need to wait for the slow function: ' + new Date().toLocaleTimeString('de'));
The output is:
Start: 16:39:20
Call slow function.
There is no need to wait for the slow function: 16:39:23
Ready at 16:39:23
By the first example, it looks like asynchron. By the second example, the function wait for the end of loop.
Do I have to use setTimeout or do I have an error in the code or am I getting it wrong? I both cases, the resolve statment is behind the large loop.
The most examples for async and await used setTimeout, but I think, it's just to simulate a break.
Thanks for your help in advance.
Best greets Pascal
The difference is that this is completely synchronous code:
This statement will block the JavaScript thread and force it to wait until all of those 4 billion iterations have taken place. Then it will move on to the next statement. Since the
console.log
executes after this, it will not execute until that loop has finished.That's why you are seeing a difference.
TL:DR
Promises and
async
functions don't offload your code to another thread. If you want to move that long-running process off the main thread, on browsers look at web workers, and on Node.js look at child processes.Details
Promises and
async
functions (which are just a syntax for creating and consuming promises) don't move your processing to any other thread, it still happens on the same thread you start the process on. The only thing they do is ensure thatthen
andcatch
callbacks are called asynchronously. They don't make your code asynchronous (other than that one thing, ensuring the callbacks happen asynchronously).So your first block using
setTimeout
just sets a timeout, returns a promise, and then when the timeout expires it blocks the main thread while your slow-running process executes. This just changes when the blocking happens a little bit, it doesn't change the fact of the blocking.You can see that effect here, notice how the counter pauses when the long-running process occurs:
Your second block not using
setTimeout
just blocks right away, because the promise executor function (the function you passnew Promise
) runs immediately and synchronously, and you're not doing anything to make it asynchronous.You can see that here; the counter pauses right away, not later:
We don't even see the before slowFunction log appear until after the long-running code has finished, because the browser never got a chance to repaint, we had the thread hogged.
Regarding
async
functions: The code in anasync
function starts out synchronous, and is synchronous until the firstawait
(or other construct, such assetTimeout
, that schedules things to execute later). Only the code after that is asynchronous (because it had to wait).Here's an example demonstrating that:
Here's the output of that:
Notice how before await occurs before after foo; it's synchronous with the call to
foo
. But then after await doesn't occur until later (becauseawait Promise.resolve()
has to make the code following it occur asynchronously; it's syntactic sugar forthen
, which promises not to call its handler synchronously even if the promise is already resolved).