I haven’t touched JS for a while. Can someone explain why am I getting such an unexpected result?
My goal is to return a result from an async function. (Or, in other words, to convert an asynchronous function into a synchronous one and return the result from it.)
Let me show it in code:
<!DOCTYPE html>
<html>
<head>
</head>
<script>
function test1()
{
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Timer fires");
resolve("Done");
}
, 2000);
});
}
async function test2()
{
console.log("Before promise");
let result = await test1();
console.log("After promise");
console.log("result=" + result);
return result;
}
</script>
<body>
<script>
let final_result = test2();
console.log("Got final result=" + final_result);
</script>
</body>
</html>
My assumption was that when I call my test2
it will wait for the result of test1
, so I would get in the log:
Before promise
Timer fires
After promise
result=Done
Got final result=Done
But what I’m getting is this:
Before promise
Got final result=[object Promise]
Timer fires
After promise
result=Done
It’s almost like let result = await test1();
executes twice. Once it returns a Promise
right away and somehow skips all the console.log
s that follow it, and then after the timer fires, it does execute all those console.log
statements.
I’m obviously missing something in the code flow of this latest JS.
2
Answers
Let me clarify the order of execution for you:
let final_result = test2();
is run, execution moves totest2
.'Before promise'
is logged in the body oftest2
.let result = await test1();
is run, the execution of the function halts until the promise returned fromtest1
resolves.'Got final result=[object Promise]'
is logged, where[object Promise]
is the pending promise returned from thetest2
function.'Timer fires'
is logged after the 2000ms timer intest1
completes.'After promise'
and'result=Done'
are logged in body oftest2
.I’m pretty sure that the order of step/log line 2 and step 4 appearing is not fully deterministic, but can’t find a reference for that.
If you want to prevent the top-level script from execution before
test2
has finished, you would need toawait
it as well (see @asportnoy’s answer), or chain athen
from it:You need to add an await in the second script tag, otherwise it will not wait for
test2()
to complete before continuing. Something like this:Note that the
type="module"
is required in order to use top-level await. If you don’t want to use that, you can use an IIFE instead: