How async await internally work? - javascript

My question is how execution wait for function result in node.js or v8
environment.
We know, node.js is single thread non blocking I/O environment.
What is internal code and how it work?
Example async function:
async function asyncCall() {
// `getCreditorId` and `getCreditorAmount` return promise
var creditorId= await getCreditorId();
var creditAmount=await getCreditorAmount(creditorId);
}
If you execute this function then first wait for creditorId then call getCreditorAmount using creditorId and again wait from creditor Amount in this async function only.
Instead of async function other execution not wait, that works fine.
Second question
If use promise for this example
getCreditorId().then((creditorId)=>{
getCreditorAmount(creditorId).then((result)=>{
// here you got the result
})
});
My assumption if async await use promise internally then async must must know which varibale use in getCreditorAmount function as parameter.
How it know ?
Might be my question is worthless?
If it has a answer then i want to know the ans.
Thanks for help.

async-await uses Generators to resolve and wait for Promise.
await is asynchronous in async-await, when compiler reach at await it stops executing and push everything into event queue and continue with synchronous code after async function. Example
function first() {
return new Promise( resolve => {
console.log(2);
resolve(3);
console.log(4);
});
}
async function f(){
console.log(1);
let r = await first();
console.log(r);
}
console.log('a');
f();
console.log('b');
Since await is asynchronous thus every other thing before await happens as usual
a
1
2
4
b
// asynchronous happens
3

async/await is just a Generator.
Take a look at these docs if you would like to learn more.
Generators
Async Function

Related

What is the point of the await keyword within an async function in terms of returning a value?

I've researched many many posts and articles, and documentation. I'm seeking deeper understanding.
From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await
The await expression causes async function execution to pause until a Promise is settled, [...]
let fetchLocation = () => {
//fetches information from satellite system and
//returns a Vector2 of lat long on earth
return new Promise(resolve => {
setTimeout(() => {
resolve({
lat: 73,
long: -24
});
}, 2000);
});
}
//async functions automatically return a promise.
let main = async() => {
//awaits the promises resolution
let result = await fetchLocation();
console.log("I'm the awaited promise result", result)
//immediately returns a promise as promise pending
return result;
}
console.log(main().then(res => console.log("I'm the original promise, just passed along by the async function, it didn 't a-wait for me", res)))
Before going down this rabbit hole, I knew async/await was syntactical sugar to make async code look synchronous.
I therefore fully expected to see main return the lat long coordinates. Instead it returns a promise.
A couple questions.
Is the MDN documentation wrong? Does it not actually pause execution? It seems that the await keyword does not actually "pause" function execution... invoking main immediately returns a Promise<pending> object. However, after it returns we receive the value of the fulfilled promise in the awaited variable result. I suppose this came from the event loop? (And an async return statement is still synchronous.)
So it seems that await unwraps a promise, and async wraps a promise, but you need to use await within async. I get that await might actually be promise.then() underneath the hood but if they want to make it fully synchronous in appearance, why not have the async function return the resolved promise value when used with await? Otherwise async await seems a bit redundant.
Is the MDN documentation wrong?
No
Does it not actually pause execution?
It pauses the execution of the async function, hands a Promise back to the calling function — because it hasn't reached the point in the async function where it knows what to return — then the execution of the calling function (and the rest of the code) continues.
However, after it returns we receive the value of the fulfilled promise in the awaited variable result. I suppose this came from the event loop?
When the event loop stops being busy (running the code that called the async function in the first place and anything else that it picks up in the meantime) and the promise that was being awaited resolves, then the async function is woken up and given the resolved value of the function to continue processing.
why not have the async function return the resolved promise value when used with await?
Because that would block the entire event loop, which is why asynchronous logic (starting with callback style APIs) was introduced into JS in the first place.
Otherwise async await seems a bit redundant.
Consider a situation where you want to request a number of URLs from an API serially (so that you don't shove too many simultaneous requests at the API):
const data = [];
for (let i = 0; i < urls.length; i++) {
const response = await fetch(urls[i]);
const response_data = await response.json();
data.push(response_data);
}
If you were to rewrite that without await then you'd probably end up with something recursive to count your way through the loop. It would be significantly more complex.
async/await makes dealing with complex combinations of promises simple, and simple promises trivial.
knew async/await was syntactical sugar to make async code look synchronous.
And it does that inside the async function and only inside it.
It doesn't really pause the function, it just allows you to write the rest of the function code as if it were. But it's really just wrapping the rest of the code of the function into a .then().
E.g.
await foo = someFunc();
console.log(foo);
is executed like
someFunc().then((foo => {
console.log(foo);
});
Since it's really still asynchronous, you can't return the resolved value, because the original calling function returns immediately. But if the calling function is also declared async, it returns a Promise, and the caller can either use await again (so it appears to be synchronous) or use .then().

How to use await with async function without creating a Promise?

I know an async function returns a Promise, so I thought of replacing this code:
const hi = function (delay) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('hi');
resolve();
},delay)
});
};
const bye = async () => {
await hi(1000);
await hi(1000);
await hi(1000);
await hi(1000);
return 'bye';
};
bye().then((msg) => {
console.log(msg);
});
with this code:
const hi = async (delay) => {
setTimeout(() => {
console.log('hi');
},delay);
};
const bye = async () => {
await hi(1000);
await hi(1000);
await hi(1000);
await hi(1000);
return 'bye';
};
bye().then((msg) => {
console.log(msg);
});
The only difference is I'm using an async function instead of a function which returns a Promise, since an async function return a promise. But the second code doesn't work as I expected it too. It just console.logs bye immediately and then after 1s console.logs 'hi' 4 times. Can you please help me understand the reason behind this?
One major difference in both code examples is related to the return value of hi function.
In the first code example, function hi returns a promise whereas in the second code example, function hi does not explicitly returns any value; as a result, the promise returned by the async function is implicitly resolved with the value of undefined without waiting for the setTimeout's callback function to execute.
A promise object doesn't makes anything asynchronous; its just a wrapper around an already asynchronous operation and the promise object notifies whether the asynchronous operation completed successfully or whether it failed.
In the first code example, you have a wrapper promise around the setTimeout. That wrapper promise is not fulfilled until resolve is called from within the callback function of the setTimeout.
In the second code example, the promise returned by the async function isn't automatically bound to the asynchronous code inside the function.
After calling setTimeout, code execution reaches the end of the hi function; As there is no explicit return statement, promise returned by the async function is fulfilled with the value of undefined. This happens before the callback function of the setTimeout is called.
What's confusing you here is the setTimeout, your await hi( will actually await, but there isn't anything to wait for, that promise will almost immediately resolve and return so all 4 of them will execute almost instantaneously, then log "bye", then after 1 second your timeout will trigger and console.log "hi".
This answer adds some additional info to the one provided by Yousaf.
To shortly answer your comment:
Thanks for the explanation. Is there any way to write the hi function without using the 'Promise' keyword?
The answer is no. To convert a function using a callback interface to one that uses a promise you will have to manually create a promise somewhere. Functions using an older interface (usually) don't return promises, therefore you cannot await them. You can only await objects that are thenable (i.e. has a "then" method). If you await a non-thenable value or object, the await statement is essentially ignored.
MDN recommends wrapping callback methods at the lowest level possible:
Creating a Promise around an old callback API
A Promise can be created from scratch using its constructor.
This should be needed only to wrap old APIs.
In an ideal world, all asynchronous functions would already return
promises. Unfortunately, some APIs still expect success and/or failure
callbacks to be passed in the old way. The most obvious example is the
setTimeout() function:
setTimeout(() => saySomething("10 seconds passed"), 10*1000);
Mixing old-style callbacks and promises is problematic. If
saySomething() fails or contains a programming error, nothing
catches it. setTimeout is to blame for this.
Luckily we can wrap setTimeout in a promise. Best practice is to
wrap problematic functions at the lowest possible level, and then
never call them directly again:
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(10*1000).then(() => saySomething("10 seconds")).catch(failureCallback);
Basically, the promise constructor takes an executor function that
lets us resolve or reject a promise manually. Since setTimeout()
doesn't really fail, we left out reject in this case.
If you would apply this info to your situation, this means wrapping the setTimeout() call within a Promise constructor like shown above.
// The only responsibility of this function is converting the old
// callback interface, to a promise interface.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Then use this new function in hi() instead of setTimeout().
async function hi(delay) {
await wait(delay);
console.log('hi');
}
A promise captures the result of an asynchronous processing that just started.
On the version of the code without promises, the asynchronous processing happens the same way as on the first version but there is nobody there waiting for it when it completes.
The second version of the hi() function is synchronous. It completes immediately. The async keyword does not have any effect on it. Also await hi() does not help, the function is still synchronous and it completes immediately.

Async/await syntax: Is there a way to define a block of code to execute after a function without blocking the execution?

I've been questionning myself recently on how to reproduce a behaviour of then/catch with an async/await syntax.
With then/catch, I can define a callback which is only executed when the Promise resolves and then continue the execution like so .
function test() {
getUsersFromDB().then(users => console.log(users));
console.log('The rest of the code here continues to execute');
[...]
// Promise resolves and logs the users value
}
For me, with async/await you can have 2 possible behaviours.
1. Wait for the function and block the rest of the execution
async function test() {
const users = await getUsersFromDB();
// Code in here is not executed until promises returns
console.log(users);
}
2. Don't wait for the return value but don't expect you promise to be fulfilled when the rest of the code executes
function test() {
const users = getUsersFromDB();
// May log undefined
console.log(users);
}
Can I reproduce the first use case using async/await ?
Using then is the simplest solution, but you can use an AIIFE:
function test() {
(async () => {
const users = await getUsersFromDB();
console.log(users);
})().catch(console.error);
console.log('The rest of the code here continues to execute');
[...]
// Promise resolves and logs the users value
}
An alternative could only be async do expressions.
So what you need is basically split the code. One piece should be executed in async/await syntax, and another one should be as usual.
First what I want to say, if you do as follows
async function test() {
console.log('The rest of the code here continues to execute');
const users = await getUsersFromDB();
// Code in here is not executed until promises returns
console.log(users);
}
that will do the trick. This may appear a little strange because we just moved the line a bit up, this is not what we wanted to do, but...
The await keyword stops execution of an async function, but we have some code that should continue working at the time when await freezes the function, that means we can't place the code after await, only before.
As far as I understand, the code tahat is indicated as "The rest of the code here continues to execute" can be asynchronous too, so the resulting example will be as follows:
async function test() {
console.log('Some synchronous code');
setImmediate(() => {
console.log('Some asynchronous code');
});
const users = await getUsersFromDB();
// Code in here is not executed until promises returns
console.log(users);
}

Does awaiting a synchronous function synchronously return a value?

I imported a function from an internal utility library that I am unfamiliar with. There is no documentation for this library and I just assumed it was asynchronous due to its name getUserDetails. I thought it was doing an http request.
I used it in an async function like this
async function getAllUserInfo(event) {
const details = await getUserDetails(event);
// other stuff
}
I was wrong in my assumption. A co-worker pointed out that is was not asynchronous. I ended up changing it, but when I was using it incorrectly it still worked. I was able to await a synchronous function and it returned the correct data.
My question is in regards to how it worked. Does prepending an await on a synchronous function make it resolve on the next tick, or does it return immediately like a synchronous function should?
It worked because await does not require its operand to be a promise! It returns the value of the awaited expression if it is not a promise.
See the documentation for the await operator
The important part is:
[rv] = await expression;
expression: A Promise or any value to wait for.
rv: Returns the fulfilled value of the promise, or the value itself if it's not a Promise.
In your case getUserDetails did not return a promise, but rather some regular user details, so the await expression just returned those details, just as if the operator was not there at all.
However, even though getUserDetails is synchronous, preceding it with await in your async function will give up control to its caller, and the "callback portion" after the await is picked up later. Here is an example script:
function f() {
console.log('In f');
}
async function g() {
console.log('Starting g');
await f();
console.log('Finishing g');
}
console.log('Starting the script')
g();
console.log('Finishing the script')
Notice the output of the script:
$ node asynctest.js
Starting the script
Starting g
In f
Finishing the script
Finishing g
Notice how the await call "paused" g, which was not able to resume until the main block finished! So the await did have an effect. If you did not put the await there, then you would have seen "Finishing g" before "Finishing the script". Try it out!
BTW the reason for the effect is that even though await can be given an expression that does not produce a promise, JS will turn a non-promise operand into a promise immediately resolved to that value. So a promise is still created and the part after await is treated as a callback, which cannot be run until the current execution flow finishes.
If you await a value that is not a promise, it is converted to a resolved promise by using Promise.resolve.
function sync(){
return 1
}
(async ()=>{
const v = await sync(); console.log(v)
})();
(async ()=>{
const v = await Promise.resolve(sync()); console.log(v)
})()

How to await an asynchronous function?

My case:
let waiting = function () {
return new Promise(resolve => {
console.log('awaiting...');
setTimeout(function () {
resolve();
}, 1000)
});
};
let waitingAsync = async function () {
console.log('start...');
await waiting();
console.log('stop...');
};
waitingAsync();
console.log('done...');
There are 2 things I don't understand in the code:
The first:
await waiting();
waiting is a synchronous function (because it doesn't have async keyword). So, why can I await a synchronous function?
The second:
Why couldn't done... message be awaited after completing waitingAsync function?
And main question: waitingAsync is an asynchronous function, why is await keyword not required when calling it? Just waitingAsync() instead of await waitingAsync().
If I can await waitingAsync(), done... message would be printed last.
This isn't a function but a value that it returns which is awaited with await statement.
async and normal functions aren't different to the caller. async just returns a promise without returning it explicitly when being called. The result of waitingAsync() call is a promise. The result of waiting() call is a promise, too, so it isn't 'synchronous'.
According to the spec, both promises and non-promises can be awaited. Non-promises are converted to promises with Promise.resolve().
console.log('done...') can't be awaited because it isn't called inside async function. And it doesn't have to be awaited because it doesn't return a promise but undefined. awaiting it would be possible within async function. These await usages are equal and equally useless, all they do is 1 tick delay:
async function ... {
...
await console.log('done...');
}
async function ... {
...
console.log('done...');
await undefined;
}
async function ... {
...
await Promise.resolve(console.log('done...'));
}
A async function does return a promise or, when it uses the await keyword, it must wait for a asynchronous function, being a Promise or another async function. In your code, waiting() is a function that returns a Promise. Then, await waiting() is correct (since it is waiting for a asynchronous function).
An async function is called as another basic functions is called. You may mark a function as async when you desire operate it as an asynchronous function and using the 'await' keyword. The 'done...' is printed because when you call asyncFunction(), it must await until waiting promise is finished. But the program is not stopped and go on showing done.... If you want to wait for it, maybe you can use asyncFunction().then( () => console.log('done...') )
Async keyword used to specify that function will be an instance of AsyncFunction so it will return Promise.
Await is used to wait for a promise resolving inside of async function.
According to a mdn - async function can contain an await expression, that pauses the execution of the async function and waits for the passed promise's resolution, and then resumes the async function's execution and returns the resolved value.
When you await a function, if that function returns a promise, its return value will be treated as the promise then value. If the promise will reject, it will be cast to an Error. If the function call returns something ohter than a thenable, well, await then just doesn't nothing.
In the other hand, when you declare an async function, its return value will be returned as a Promise, and any Error thrown from it will be casted to a rejected Promise.
You can use await only within an async declared function.
that's just about async and awaitare, just automatic casting to promises. You don't actually need code using await and async to be really asynchronous (while, well, it's not really useful).
A quick demonstration:
//Will return the string 'Promise' if called through `await`
function getPromise(){
return Promise.resolve('Promise');
}
//Casted to Promise.reject thrught await
function throwError(){
return Promise.reject('error');
}
function get(){
return 'something simple';
}
async function getAsync() {
var response = await getPromise();
return response;
}
//await will cast the rejected Promise to an error
async function getErrorAsync() {
var response = await throwError();
return response;
}
async function simpleGet(){
return get();
}
async function redundantGet(){
return await get();
}
async function catchTheError(){
try{
await throwError();
}
catch(e){
console.log('an error: ' + e );
}
return 'whatever';
}
getAsync().then( console.log ); //Promise
getErrorAsync().catch( console.log ); //error
simpleGet().then( console.log ); //something simple
redundantGet().then( console.log ); //something simple
catchTheError(); //will log 'an error: error'.
So:
waiting is a synchronous function (because it doesn't have async keyword). So, why can I await a synchronous function?
Because you can. The only thing await does is to resolve promise to real values and errors. You don't actually need the function to return a promise.
Why couldn't done... message be awaited after completing waitingAsync function?
async and await only makes your code to behave as it would be synchronous iside asyncdeclared functions. Your last console.log('done') is outside any async function, so it will be just logged before that function ends, since it is asynchronous.
And main question: waitingAsync is an asynchronous function, why is await keyword not required when calling it? Just waitingAsync() instead of await waitingAsync().
Because async keyword casts values to promises -and allows to use await- and nothing more. In fact, since you can only use await inside async functions... you can't expect async functions to be called through await, you would need infinite asyncfunctions :-D.
Before diving in, it's good to notice a few things.
Any reader of the code snippet
let waiting = function () {
return new Promise(resolve => {
console.log('awaiting...');
setTimeout(function () { resolve(); }, 1000);
});
};
let waitingAsync = async function () {
console.log('start...');
await waiting();
console.log('stop...');
};
waitingAsync();
console.log('done...');
may be mislead to believe that the output will be
start...
awaiting...
stop...
done...
while – as you have already noted – done... gets printed before
stop....
The reason is that waitingAsync(); is a call to an asynchronous function,
while console.log('done...'); is just a normal sequential/synchronous
statement that gets carried out right away.
Question 1:
waiting is a synchronous function (because it doesn't have async
keyword) [?]
Answer:
False. The function waiting is asynchronous – it returns
a Promise.
Question 2:
Why couldn't done... message be awaited after completing waitingAsync
function?
Answer:
Because console.log('done...') is not asynchronous.
(It does not return a Promise.)
Question 3:
And main question: waitingAsync is an asynchronous function, why is
await keyword not required when calling it?
Answer:
Well, in your example waitingAsync does not return any value. -
If it would return a value that you care about, then you would need to await
it to get it.
(Hello world! in my Stack Snippet below.)
Question 4:
If I can await waitingAsync(), [the] done... message would be printed
last [?]
Answer:
That depends on what exactly you mean. – See my Stack Snippet below!
As long as the Done! message is printed within the same callback as the call
await waitingAsync(), the answer is Yes!
But if you put console.log('done...?') after the call to the asynchronous
function that encloses await waitingAsync() then the answer is No!
When running the snippet below, pay attention to the order of the output!
Also notice how it takes 1400 ms for Promise resolved! to show up.
function waiting () {
return new Promise(resolve => {
console.log('awaiting...');
setTimeout(function () {
resolve('Hello world!');
console.log('Promise resolved!');
}, 1400);
});
}
async function waitingAsync () {
console.log('start...');
const toBeReturned = await waiting();
console.log('stop...');
return toBeReturned;
}
(async () => {
console.log('Heads up! The next line makes an asynchronous call.');
console.log('Result: ' + await waitingAsync()); // 'Hello world!'
console.log('Done! This will be printed LAST! - Agreed?');
})();
console.log('done...?? This is LAST in the CODE. - I awaited \
"waitingAsync()" above. - So will this be printed at the very end??');
.as-console-wrapper { max-height: 100% !important; top: 0; }
The last asynchronous function is anonymous – without name – and gets
called immediately.
In fact, this is the only function that gets called directly in the snippet.
The function waitingAsync is only called indirectly (by the anonymous
function), and the function waiting is also called indirectly
(by waitingAsync).
A take away lesson
Don't ever put sequential/synchronous code after and outside a call to
an asynchronous function!
You will just confuse yourself if you do. – And even if you don't get
confused, other readers of your code almost certainly will be.

Categories

Resources