I thought I had a pretty good understanding of async await until I tried this:
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('what'), 10000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('?'), 15000);
});
async function asyncTest() {
console.time();
const p1 = await promise1;
if (p1 === 'what') {
var p2 = await promise2;
}
console.log(p1, p2);
console.timeEnd();
}
asyncTest()
After 15000ms, asyncTest
is logging p1
& p2
. If instead promise1
and promise2
are transformed into functions that return these promises, execution time is then 25000ms. I have no idea what's going on. Could anyone care to explain this?
Writing async code may be considered the first step for writing concurrent code. Since async/await is just a pattern, it doesn't make javascript any more concurrent or asynchronous than callbacks did. But it does make it exponentially easier to read it.
Concurrency is having two tasks run in parallel on separate threads. However, asynchronous methods run in parallel but on the same 1 thread.
It is concurrent, in the sense that many outstanding asychronous operations may be in progress at any time. It may or may not be multithreaded. By default, await will schedule the continuation back to the "current execution context".
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active.
The issues is that your Promise callbacks are invoked immediately after you declare them.
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('what'), 10000);
});
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('?'), 15000);
});
At this point, both callbacks have been invoked. 10000ms from this point, promise1
will resolve. 15000ms from this point, promise2
will resolve.
async function asyncTest() {
console.time();
const p1 = await promise1;
if (p1 === 'what') {
var p2 = await promise2;
}
console.log(p1, p2);
console.timeEnd();
}
asyncTest()
At this point, as both callbacks have already been invoked, both will be resolved within 15000ms, which is what you observed.
In order to stretch this to the 25000ms you were expecting, try rewriting the Promises as follows:
const promise1 = () => new Promise((resolve, reject) => {
setTimeout(() => resolve('what'), 10000);
});
const promise2 = () => new Promise((resolve, reject) => {
setTimeout(() => resolve('?'), 15000);
});
Note these are now function expressions that will not be invoked immediately. Then rewrite your asyncTest
function to invoke these expressions instead of simply await the already executing Promises:
async function asyncTest() {
console.time();
const p1 = await promise1();
if (p1 === 'what') {
var p2 = await promise2();
}
console.log(p1, p2);
console.timeEnd();
}
This will force promise2
to wait until promise1
is completed before beginning execution.
With the code in its current state:
You run setTimeout
and assign a promise that will handle its result to promise1
. Immediately after, you do the same thing for promise2
.
So promise2 resolves about five seconds after promise1.
If you change the code so that promise1
and promise2
are functions, then:
You run setTimeout
return a promise that will handle its result to await
. It will wait until the promise resolves 10 seconds later. Then it will assign the result to p1
.
Then (i.e. after 10 seconds have passed instead of immediately) it will do the same thing for p2
.
In short:
In the first example, you don't wait for promise1 before setting promise2 going.
After making the change you describe, you do await
promise1 before setting promise2 going.
In the first example, two promises fire-off instantly at the beginning, and by the time when browser executes line var p2 = await promise2;
the promise2 is on-half way to resolve and await
statement pauses for 5000 ms.
console.log('promise1 created');
const promise1 = new Promise((resolve, reject) => {
setTimeout(() => resolve('what'), 10000);
});
console.log('promise2 created');
const promise2 = new Promise((resolve, reject) => {
setTimeout(() => resolve('?'), 15000);
});
async function asyncTest() {
console.time();
const p1 = await promise1;
if (p1 === 'what') {
var p2 = await promise2;
}
console.log(p1, p2);
console.timeEnd();
}
asyncTest();
In the second example, you fire promises only when browser reaches the line where the function firing promise is called. So at line var p2 = await promise2();
the second promise is created and await
statement pauses for 15000 ms. Thus total execution time is 25000 ms.
const promise1 = () => {
console.log('promise1 created');
return new Promise((resolve, reject) => {
setTimeout(() => resolve('what'), 10000);
})
};
const promise2 = () => {
console.log('promise2 created');
return new Promise((resolve, reject) => {
setTimeout(() => resolve('?'), 15000);
})
};
async function asyncTest() {
console.time();
const p1 = await promise1();
if (p1 === 'what') {
var p2 = await promise2();
}
console.log(p1, p2);
console.timeEnd();
}
asyncTest();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With