Despite Await the function is being executed instantly - javascript

I am new to Javascript and am facing trouble dealing with Async/Await. Here is my code, as per my understanding adding await puts on hold the function
Here, inside foo, it should put on hold the code at checker() and move to running the commands outside foo, but instead it executes the checker() function before console.log('the end').
function checker() {
console.log('inside checker');
return "Ok"
}
async function foo() {
let a = await checker(); // Shouldn't using await here let next line outside foo to execute
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
// Output coming is:
//1
//inside checker
//the end
//mid Ok
Can someone please tell me what properties are making it to behave this way. I know there's something that I am missing but can't figure out what.

Your checker function is not asynchronous, but you also need to do something that is actually async within it.
At the moment, all of the promises are instantly resolved which provides no opportunity for later code to run.
We need to actually create a promise, merely defining a function as async isn't enough unless something inside is returning a promise, so we return a new promise which is resolved by the setTimeout callback.
Note that the timeout period is 0 which is enough to cause the javascript event loop to be invoked, which allows the next statement(s) after calling foo to be processed. Changing this to any positive integer will change the execution time but not the order of events.
function checker() {
return new Promise(resolve => {
setTimeout(() => resolve('Ok'), 0)
})
}
function foo() {
let a = checker();
console.log(new Date(), "mid");
return a
}
(async () => {
console.log(new Date(), 'start');
foo().then(v => console.log(new Date(), 'eventually', v));
console.log(new Date(), 'the end');
})()

You didn't define your function as async
function checker() {
console.log('inside checker');
return "Ok"
}
It should be
async function checker() {
console.log('inside checker');
return "Ok"
}

await tells your code to wait for the function to finish. If you want to continue running without waiting, then you shouldn't use the await keyword. async also needs to be on the function that you want to run asynchronously, in this case checker()
async function checker() {
console.log('inside checker');
return "Ok"
}
function foo() {
let a = checker();
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');

foo is an async function, ie the code inside it will wait if you use the await keyword
But the foo function returns a promise. so if you want to wait for foo either use
await foo();
or use
foo().then(() => { console.log('the end'); })

Related

Understanding the order of async calls and setTimeouts

The code below contains a function (logger) that sets a timeout, then consoles an async function, then consoles an element ('c').
The output here is 'a', 'b', 'c'.
How is it that 'c' waits for the other two to return? The await call is inside a console.log, so I thought the 'c' console will go ahead and execute since await isn't at the beginning of the console call for 'b'.
In other words, I thought the output should be 'c','a','b'.
Any enlightenment here would be much appreciated!
async function apiCall() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('b');
}, 50);
});
}
async function logger() {
setTimeout(() => console.log('a'), 10);
console.log(await apiCall());
console.log('c');
}
logger();
The await inside the console.log() call represents a point at which the logger() function will return an intermediate promise. Note that the line of code is equivalent to
let p = await apiCall();
console.log(p);
The expression parameters in a function call are evaluated before the function is called. Thus, the whole function (logger()) has to wait for the promise to resolve before it can proceed to call console.log().

How to properly use async/await within function? [duplicate]

Given the code samples below, is there any difference in behavior, and, if so, what are those differences?
return await promise
async function delay1Second() {
return (await delay(1000));
}
return promise
async function delay1Second() {
return delay(1000);
}
As I understand it, the first would have error-handling within the async function, and errors would bubble out of the async function's Promise. However, the second would require one less tick. Is this correct?
This snippet is just a common function to return a Promise for reference.
function delay(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
Most of the time, there is no observable difference between return and return await. Both versions of delay1Second have the exact same observable behavior (but depending on the implementation, the return await version might use slightly more memory because an intermediate Promise object might be created).
However, as #PitaJ pointed out, there is one case where there is a difference: if the return or return await is nested in a try-catch block. Consider this example
async function rejectionWithReturnAwait () {
try {
return await Promise.reject(new Error())
} catch (e) {
return 'Saved!'
}
}
async function rejectionWithReturn () {
try {
return Promise.reject(new Error())
} catch (e) {
return 'Saved!'
}
}
In the first version, the async function awaits the rejected promise before returning its result, which causes the rejection to be turned into an exception and the catch clause to be reached; the function will thus return a promise resolving to the string "Saved!".
The second version of the function, however, does return the rejected promise directly without awaiting it within the async function, which means that the catch case is not called and the caller gets the rejection instead.
As other answers mentioned, there is likely a slight performance benefit when letting the promise bubble up by returning it directly — simply because you don’t have to await the result first and then wrap it with another promise again. However, no one has talked about tail call optimization yet.
Tail call optimization, or “proper tail calls”, is a technique that the interpreter uses to optimize the call stack. Currently, not many runtimes support it yet — even though it’s technically part of the ES6 Standard — but it’s possible support might be added in the future, so you can prepare for that by writing good code in the present.
In a nutshell, TCO (or PTC) optimizes the call stack by not opening a new frame for a function that is directly returned by another function. Instead, it reuses the same frame.
async function delay1Second() {
return delay(1000);
}
Since delay() is directly returned by delay1Second(), runtimes supporting PTC will first open a frame for delay1Second() (the outer function), but then instead of opening another frame for delay() (the inner function), it will just reuse the same frame that was opened for the outer function. This optimizes the stack because it can prevent a stack overflow (hehe) with very large recursive functions, e.g., fibonacci(5e+25). Essentially it becomes a loop, which is much faster.
PTC is only enabled when the inner function is directly returned. It’s not used when the result of the function is altered before it is returned, for example, if you had return (delay(1000) || null), or return await delay(1000).
But like I said, most runtimes and browsers don’t support PTC yet, so it probably doesn’t make a huge difference now, but it couldn’t hurt to future-proof your code.
Read more in this question: Node.js: Are there optimizations for tail calls in async functions?
Noticeable difference: Promise rejection gets handled at different places
return somePromise will pass somePromise to the call site, and await somePromise to settle at call site (if there is any). Therefore, if somePromise is rejected, it will not be handled by the local catch block, but the call site's catch block.
async function foo () {
try {
return Promise.reject();
} catch (e) {
console.log('IN');
}
}
(async function main () {
try {
let a = await foo();
} catch (e) {
console.log('OUT');
}
})();
// 'OUT'
return await somePromise will first await somePromise to settle locally. Therefore, the value or Exception will first be handled locally. => Local catch block will be executed if somePromise is rejected.
async function foo () {
try {
return await Promise.reject();
} catch (e) {
console.log('IN');
}
}
(async function main () {
try {
let a = await foo();
} catch (e) {
console.log('OUT');
}
})();
// 'IN'
Reason: return await Promise awaits both locally and outside, return Promise awaits only outside
Detailed Steps:
return Promise
async function delay1Second() {
return delay(1000);
}
call delay1Second();
const result = await delay1Second();
Inside delay1Second(), function delay(1000) returns a promise immediately with [[PromiseStatus]]: 'pending. Let's call it delayPromise.
async function delay1Second() {
return delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
Async functions will wrap their return value inside Promise.resolve()(Source). Because delay1Second is an async function, we have:
const result = await Promise.resolve(delayPromise);
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
Promise.resolve(delayPromise) returns delayPromise without doing anything because the input is already a promise (see MDN Promise.resolve):
const result = await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
await waits until the delayPromise is settled.
IF delayPromise is fulfilled with PromiseValue=1:
const result = 1;
ELSE is delayPromise is rejected:
// jump to catch block if there is any
return await Promise
async function delay1Second() {
return await delay(1000);
}
call delay1Second();
const result = await delay1Second();
Inside delay1Second(), function delay(1000) returns a promise immediately with [[PromiseStatus]]: 'pending. Let's call it delayPromise.
async function delay1Second() {
return await delayPromise;
// delayPromise.[[PromiseStatus]]: 'pending'
// delayPromise.[[PromiseValue]]: undefined
}
Local await will wait until delayPromise gets settled.
Case 1: delayPromise is fulfilled with PromiseValue=1:
async function delay1Second() {
return 1;
}
const result = await Promise.resolve(1); // let's call it "newPromise"
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: 1
const result = 1;
Case 2: delayPromise is rejected:
// jump to catch block inside `delay1Second` if there is any
// let's say a value -1 is returned in the end
const result = await Promise.resolve(-1); // call it newPromise
const result = await newPromise;
// newPromise.[[PromiseStatus]]: 'resolved'
// newPromise.[[PromiseValue]]: -1
const result = -1;
Glossary:
Settle: Promise.[[PromiseStatus]] changes from pending to resolved or rejected
This is a hard question to answer, because it depends in practice on how your transpiler (probably babel) actually renders async/await. The things that are clear regardless:
Both implementations should behave the same, though the first implementation may have one less Promise in the chain.
Especially if you drop the unnecessary await, the second version would not require any extra code from the transpiler, while the first one does.
So from a code performance and debugging perspective, the second version is preferable, though only very slightly so, while the first version has a slight legibility benefit, in that it clearly indicates that it returns a promise.
In our project, we decided to always use 'return await'.
The argument is that "the risk of forgetting to add the 'await' when later on a try-catch block is put around the return expression justifies having the redundant 'await' now."
Here is a typescript example that you can run and convince yourself that you need that "return await"
async function test() {
try {
return await throwErr(); // this is correct
// return throwErr(); // this will prevent inner catch to ever to be reached
}
catch (err) {
console.log("inner catch is reached")
return
}
}
const throwErr = async () => {
throw("Fake error")
}
void test().then(() => {
console.log("done")
}).catch(e => {
console.log("outer catch is reached")
});
here i leave some code practical for you can undertand it the diferrence
let x = async function () {
return new Promise((res, rej) => {
setTimeout(async function () {
console.log("finished 1");
return await new Promise((resolve, reject) => { // delete the return and you will see the difference
setTimeout(function () {
resolve("woo2");
console.log("finished 2");
}, 5000);
});
res("woo1");
}, 3000);
});
};
(async function () {
var counter = 0;
const a = setInterval(function () { // counter for every second, this is just to see the precision and understand the code
if (counter == 7) {
clearInterval(a);
}
console.log(counter);
counter = counter + 1;
}, 1000);
console.time("time1");
console.log("hello i starting first of all");
await x();
console.log("more code...");
console.timeEnd("time1");
})();
the function "x" just is a function async than it have other fucn
if will delete the return it print "more code..."
the variable x is just an asynchronous function that in turn has another asynchronous function, in the main of the code we invoke a wait to call the function of the variable x, when it completes it follows the sequence of the code, that would be normal for "async / await ", but inside the x function there is another asynchronous function, and this returns a promise or returns a" promise "it will stay inside the x function, forgetting the main code, that is, it will not print the" console.log ("more code .. "), on the other hand if we put" await "it will wait for every function that completes and finally follows the normal sequence of the main code.
below the "console.log (" finished 1 "delete the" return ", you will see the behavior.

.then() doesn't wait till async function resolves promise?

I have two functions. First contains jQuery.get().done() and it's return value is inside done() callback function, as showed below. (I have no idea if using jQuery matters here)
I may not be understanding something, but my functions looks similar to those in first w3 example: https://www.w3schools.com/js/js_async.asp
async function A(){
jQuery.get("example.com").done(function(result){
if (result.indexOf("Example")){
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
})
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
But the output is:
Res:undefined
// here some time passes for A() to complete.
succes
So I can't understand why .then() doesn't wait for function A() to complete and resolve promise, but instead it acts immediately while result is not defined yet ?
This is much better written using actual promises (which jQuery supports) and await as follows:
async function A() {
const result = await jQuery.get("example.com");
if (result.indexOf("Example") !== -1) {
console.log("sucess");
return 1;
} else {
console.log("Fail");
return -1;
}
}
Notes:
Stop using jQuery's .done(). It's non-standard. Use .then() or await.
Don't mix await with .done() or with .then(). Use one model or the other.
There's no need for the res intermediate variable. When you get rid of the .done(), you can just return the value directly.
Note, .indexOf() does not return a boolean. It returns -1 if not found and an index of the position if found. Best not to treat its return value as a boolean.
This isn't really a jQuery thing in particular. It's just async JS in general. I'm not sure you really need the .done() part at all since you're using promises.
But anyway, you have two basic problems.
You need to return something inside of function A, not inside .done(). So you can return jQuery.get().
In function B, you want to wait for function A to complete before hitting the .then() block. That means function B is also async. (In the simple example below you can omit the async keyword on function A.) You need to declare function B as async and then await the completion of function A.
 
function A() {
return jQuery.get("example.com").done(function(result) {
if (result.indexOf("Example")) {
console.log("sucess", result);
} else {
console.log("Fail", result);
}
});
}
async function B() {
await A().then(function(result) {
console.log("Res:");
// moved to a separate console log, otherwise dev tools might print
// a lot of [objectObject] instead of the actual result
console.log(result);
})
}
B();
If you want to do other stuff inside of function A and then eventually return the result, you can play around with something more like
async function A() {
const response = await jQuery.get('example.com');
// more stuff…
return response;
}
I fixed it by moving return statement outside from the .done(function(){}) and by adding await before jQuery chain. And instead of returning value inside that callback function, now I only pass there value to variable, which is later returned outside of that callback function.
async function A(){
let res = 0;
await jQuery.get("example.com").done(function(result){ //await was added
if (result.indexOf("Example")){
console.log("sucess");
res = 1; // value is passed to variable, which is returned as result outside this callback function
} else {
console.log("Fail");
res = -1;
}
})
return res; // return statement is outside the callback function
}
function B(){
A().then(function(result){
console.log("Res:" + result);
})
}
B();
I guess the problem was, as #cjl750's answer says, that return statement inside the callback function isn't "seen" as a "true return statement" of that function. So function B() probably saw function A() as a function, which doesn't return anything.
EDIT
I've rewritten the code using $.Deferred() object. It's probably better now. Await is now moved to function B(), it doesn't wait for jQuery chain anymore.
function A(){
var dfd = $.Deferred();
jQuery.get("google.com").then(function(result){
if (result.indexOf("Example")){
console.log("sucess");
dfd.resolve(1);
} else {
console.log("Fail");
dfd.resolve(-1);
}
})
return dfd.promise();
}
async function B(){
await A().then(function(result){
console.log("Res:" + result);
})
}
B();

What is the control flow through this code?

The following code (yes I know it is not idiomatic) prints 1,2. But I expected it to print 2,1.
(async()=>{
let resolve;
new Promise((r)=>{
resolve = r
}).then(()=>console.log('1'))
await resolve();
console.log('2')
})()
1. (async()=>{
2. let resolve;
3. new Promise((r)=>{
4. resolve = r
5. }).then(()=>console.log('1'))
6. await resolve();
7. console.log('2')
8. })()
Expected control flow:
Line 1: instantiate an anonymous async function expression
Line 8: ...and immediately call it
Line 2: variable declaration
Line 3 & 4: Instantiate Promise, run the executor function, assign the variable
Line 5: configure the `then` with the callback
Line 6: Schedule evaluation of the `then` for the next microtask
Line 6 (contd.): `resolve()` synchronously returns `undefined`
Line 6 (contd.): `await` triggered with undefined (unsure of action)
Line 7: Print `2`
Line 8: Pop execution contexts from stack
<on next microtask>
Line 5: Push execution context for anonymous function onto stack, print `1`
Why is this wrong? Does the async keyword schedule the expression to the right to be on the next microtask, keeping the order 1,2?
The issue seems to be the usage of await. When the keyword is encountered, the JavaScript interpreter will immediately pause the rest of the function and only resume the rest of the execution after the Promise is resolved. If you await nonPromiseValue it's treated as if you've created it via Promise.resolve() and is essentially equivalent to
Promise.resolve(nonPromiseValue)
.then((resolvedValue) => {
resolvedValue;
})
Or even more generally this:
await <await expression>;
<rest of body>;
return <return expression>;
Works like this:
Promise.resolve(<await expression>)
.then(resolvedValue => {
resolvedValue();
<rest of body>;
return <return expression>;
});
Thus and then you'd still have the rest of the body of the function put on the microtask queue and executed at least the next time the event loop picks a task.
NOTE: I'm omitting some details because the engine would be pausing and unpausing the execution, so if the await expression is part of another statement, you might get slightly different behaviour than what you'd expect at a glance, yet still the reason is immediate pausing when await is encountered. Thus expressions before and after an await keyword would be evaluated at different times and thus might have a different result.
At any rate, here is an example:
async function foo() {
console.log("foo - start");
"any value without await";
console.log("foo - end")
}
async function bar() {
console.log("bar - start");
await "any value";
console.log("bar - end")
}
console.log('start');
foo();
bar();
console.log('end');
For foo() the execution is straight forward:
Call the function.
Execute every line in the body.
Finish.
Yes, it's async but it's still executed synchronously. The only difference here is that the result would be a Promise but since it's all synchronous and there is no return keyword, then it's just implicitly Promise.resolve(undefined).
However, for bar() the execution is different:
Call the function.
Execute every line until you encounter await.
Turn the rest of the function to a Promise.
Pause and wait until the Promise is resolved.
Since we've await-ed a non-Promise this will happen immediately the next event loop iteration.
Continue the execution.
So, in fact the body of the function is wrapped in a Promise behind the scenes, so we actually run something similar to this:
async function bar() {
console.log("bar - start");
Promise.resolve("any value") //<-- await "any value";
.then((resolvedValue) => {
resolvedValue; //<-- nothing is done with it but it's what we awaited
console.log("bar - end"); //<-- the rest of the body of `bar()`
})
}
console.log('start');
bar();
console.log('end');
This is a simplified view but it's to just help visualise the fact that await will always halt execution and resume later. It uses the same Promise mechanics as usual and would delay the rest of the body for a later iteration of the event loop via a microtask but it's automatically handled for you.
Were we actually await-ing a real Promise, then you'd still get the equivalent behaviour:
async function bazAwait() {
console.log("bazAwait - start");
const result = await new Promise(resolve => resolve("some Promise value"));
console.log("bazAwait - end", result); //<-- the rest of the body of `bazAwait()`
}
async function bazPromiseEquivalent() {
console.log("bazPromiseEquivalent - start");
new Promise(resolve => resolve("some Promise value"))//<-- the awaited Promise
.then((promiseVal) => { //<-- the value the Promise resolves with
const result = promiseVal; //<-- the binding for the resolved value
console.log("bazPromiseEquivalent - end", result); //<-- the rest of the body of `bazPromiseEquivalent()`
});
}
console.log('start');
bazAwait();
bazPromiseEquivalent();
console.log('end');
I heavily suspect this is done in order to keep the behaviour the same regardless of whether or not await a Promise. Otherwise if you had a line like await myValue you'd get different execution depending on what myValue holds and it will not be obvious until you actually check that.
The following code appears to demonstrate how code after an await is treated as a microtask, similar to a then.
A tight indirectly-recursive loop of microtasks is started, that prints the first five integers to the console.
An async function is invoked synchronously. A string inside foo 2 is printed to the console after an await.
I included a generator function to remind us that they are synchronous.
async iterator included for completeness.
Note the interleaving with the "then tasks."
function printNums() {
let counter = 0
function go() {
console.log(counter++)
if(counter < 5) Promise.resolve().then(go)
}
Promise.resolve().then(go)
}
printNums()
async function foo() {
console.log('inside foo 1')
await 1
console.log('inside foo 2')
}
requestAnimationFrame(() => console.log('raf complete')) // ~16ms
setTimeout(() => console.log('macrotask complete')) // ~4ms
console.log('synch')
const syncIterable = {
*[Symbol.iterator]() {
console.log('starting sync iterable')
yield 'a'
yield 'b'
}
}
async function printSyncIterable() {
for(let y of syncIterable) {
console.log(y)
}
}
printSyncIterable()
foo().then(() => console.log('done'))
const asyncIterable = {
async *[Symbol.asyncIterator]() {
console.log('starting async iterable')
yield '⛱'
yield '🍿'
}
}
async function printAsyncIterable() {
for await(let z of asyncIterable) {
console.log(z)
}
}
printAsyncIterable()

How do I get this if statement to finish executing before the rest of the code runs?

This is a simple version of what I'm trying to do in my application. I have an if statement which evaluates the result of a function call and then populates an array if the statement comes back as true. AFTER the if statement is completely finished, I want to run some more code such as the console.log as seen below.
I understand that the if's evaluation is taking too long to finish and javascript just continues to the console.log because of its asynchronicity. How do I make the code wait for the if statement to complete?
var tabs = [];
if (isTrue()) {
tabs.push('some string');
}
console.log(tabs[1]);
function isTrue() {
setTimeout(function() {
return true;
}, 500)
}
You can just wrap your code in a Promise and consume the returned values by calling then on it:
var tabs = [];
isTrue().then(res => {
if (res) {
tabs.push('some string');
}
return tabs;
}).then(arr => {
console.log(arr);
});
function isTrue() {
//Just wrap your existing code in a Promise constructor
return new Promise((resolve, reject) => {
setTimeout(() => {
//Pass whatever value you want to consume later to resolve
resolve(true);
}, 500)
});
}
You could pass a callback to the isTrue() function, something like:
function isTrue(_callback) {
setTimeout(function() {
// code here
// Call the callback when done
if (typeof(_callback) === 'function')
_callback(tabs);
});
}
function showTabs(tabs) {
console.log(tabs[1]);
}
isTrue(showTabs);
Ought to work.
Using modern javascript, you can achieve that using promises and async/await:
const isTrue = () => new Promise(resolve => setTimeout(resolve, 500, true));
// you can only use `await` inside an `async` function
async function main() {
// better use `let` instead of `var` since `let` is block scoped,
// see:
// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let>
let tabs = [];
if (await isTrue()) {
tabs.push('some string');
}
// array's index start by 0, not 1
console.log(tabs[0]);
}
main();
(this code also use arrow functions for isTrue.)
isTrue() returns undefined. The return true inside of the setTimeout callback will return back to the timeout call, not to the isTrue() call. The code executes immeadiately and there is no asynchronity involved (except for that timer that does nothing).

Categories

Resources