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.
Related
I have this piece of code and I'm struggling to understand why the log order is "1,3,2".
(async () => {
const doSomething = async () => {
console.log("1");
};
await doSomething();
console.log("2");
})();
console.log("3");
Async/await is implemented under the hood with promises. With promises even if a promise resolves immediately the callback within the then is added as a microtask, and the current callstack execution continues. Then once the call stack is completed the microtasks are run.
So the way I read the code, the await keyword before the doSomething() function means that the rest of the code in the function after the await will be wrapped in a then call, giving control back to the caller of the function. Thus "3" should be logged first, so the order should be "3,1,2"?
What is the control flow? What actually happens when the javascript translator comes across an await keyword?
the await keyword before the doSomething() function means that the rest of the code in the function after the await will be wrapped in a then call, giving control back to the caller of the function.
Yes:
(() => {
const doSomething = () => {
console.log("1");
return Promise.resolve();
};
return doSomething().then(() => {
console.log("2");
});
})();
console.log("3");
Thus "3" should be logged first
No. Logging "1" is not delayed by any 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.
I was learning asynchrony in JS and came across Async/Await. Then, I came across this code:
function scaryClown() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 2000);
});
}
async function msg() {
const msg = await scaryClown();
console.log('Message:', msg);
}
msg(); // Message: 🤡 <-- after 2 seconds
Thus, I have questions on the above code. Firstly, how can async function msg() return message value if the function itself returns only undefined Promise, that is, the function does not explicitly use return keyword. Secondly, does await returns Promise or value itself having been unwrapped from Promise?
function scaryClown() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 2000);
});
}
The above function is a function which returns a promise when it is called, but will only be resolved after 2 seconds.
async function msg() {
const msg = await scaryClown();
console.log('Message:', msg);
}
the above function is asynchronous function which awaits for the promise to be resolved (in your case, after 2 seconds) and then only the console.log() triggers.
Note: any lines of code below the function msg() gets executed irrespective of the promise and the asynchronous function.
Running code snippet
function scaryClown() {
return new Promise(resolve => {
setTimeout(() => {
resolve('🤡');
}, 2000);
});
}
async function msg() {
console.log(scaryClown()); // try without await, so it will not wait for the result and prints first, but an unresolved promise
const msg = await scaryClown(); // actual result which is resolved, because we awaited
console.log('Message:', msg); // Prints once the resolved value is available.
}
msg(); //executes first but only prints the value once it is resolved.
console.log('I will continue executing irrespective of async func msg()');
async function msg() {
const msg = await scaryClown();
console.log('Message:', msg);
}
await resolves promise and return resolved value. so above code with then can be written like below. hope this makes you understand async await.
function msg() {
scaryClown().then(msg => {
console.log('Message:', msg);
});
}
This is what happens:
When the async function (i.e. msg) is invoked, it creates a promise object (let's call it P), which it will return when it deals with an await expression. scaryClown() executes, which sets the timer and returns yet another promise object; let's call it Q. Then await is processed: at that moment the function returns the promise P. This promise is not resolved at that moment; it is pending.
If then there is any other code that followed the call of msg(), then that is executed like would be the case after any function call. Execution continues until the call stack is empty.
Then, some time later the timer event that was scheduled by scaryClown() will fire, and the corresponding promise Q resolves. Because this promise Q was in an await expression, this resolution triggers a restoration of the execution context of msg(), where the await expression is now evaluated to be Q's resolved value, i.e. "🤡".
The variable msg gets this value assigned, and it is displayed with console.log. Then the function completes, in this particular case without any explicit return. Remember that the function had already returned, so this is not really a normal return: code execution really ends here, as there is nothing on the call stack. This makes the promise P resolve. If there had been an explicit return statement, with a value, the promise P would have been resolved with that value. But since there is no such return statement in your example, promise P resolves with undefined.
As you don't do anything with the value returned by msg(), you don't really see what it returns. If you would have done:
msg().then(console.log);
... you would have seen undefined in the console.
Your questions:
how can async function msg() return message value if the function itself returns only undefined Promise, that is, the function does not explicitly use return keyword.
The msg() call does currently not provide you with the message value. Instead it uses console.log to output it, but that is not the value returned by msg(). The returned value is a promise. Even if it had an explicit return keyword, it would still not make msg() return something else than a promise. The only difference would be what value that promise would eventually resolve to.
does await returns Promise or value itself having been unwrapped from Promise?
await does two things at two different moments in time. First it makes the function return to the caller. Then, when the promise that it awaits resolves, it makes the function continue to run again, and await represents at that moment the promised value, which can therefore be assigned to a variable (or used in another way).
I personally don't use the verb "unwrapped" when talking about promises. But yes, the expression await promise evaluates (asynchronously) to the value that promise fulfils to.
I would like to do the following and keep in mind it actually works for me. my question is what happens and Is possible to call async usrs() func from non async componentDidMount() func?
if it is not possible why it is working for me by calling this.usrs(usrs) instead of await this.usrs(usrs);
let outState = {};
class A extends Component{
componentDidMount(){
this.usrs(usrs);
}
getData(usr){
return db.collection('a/'+usr+'/bb').get().then(snap=>{
for(i = snap.docs.length-1; i>=0; i--){
outState[usr] = [...outState[usr], snap.docs[i].data()];
if(i === 0) return outState;
}
return false;
});
}
async usrs(usrs){
let os = {}, data = {};
for(i = usrs.length-1; i>=0; i--){
os = await this.getData(usrs[i]);
if(os){
data = { ...data, ...os };
if (i === 0) {
this.setState({ ...this.state, ...data });
}
}
}
}
}
You only need await if the caller needs to wait for the function to be done, for instance when it needs the result of the function, or when it needs to wait for some state/data change that the function causes. If there is no such dependency, you can just 'fire and forget', by not using the await keyword.
As others mentioned, you could use .then as well, but the basic rule is the same: you do that, when you have something specific to do after the function is done. It can be omitted otherwise.
So concretely: With 'caller', I simply mean the function that calls the async function. In your case that would be componentDidMount. The options are then quite simple:
Keep as is. usrs() will be run in the background completely and componentDidMount will continue running until its end.
Use await, so componentDidMount will wait for the return of usrs().
Use usrs().then(), so componentDidMount can continue, but the code specified in .then() is invoked after usrs() returns, if you need to do something that has to happen after usrs() is done.
We use await when we need to call and wait for async function or Promise
In your case when you call it without await inside your componentDidMount, your function will work but your componentDidMount will not wait for that function to completely finishes.
Also if you don't want to use await and you don't want to wait inside componentDidMount, but you want to get notified when your async function finishes, you can use .then instead. Because async functions returns Promise
Here is your componentDidMount with .then
Notice that in this example this.doSomethingElse will call before the this.usrs is complete, and you only will be notified inside .then about your this.usrs result when it finished:
componentDidMount(){
this.usrs(usrs).then(() => {
// Your functions completely finished
})
.catch(err => {
// There was an error
});
this.doSomethingElse();
}
The async work before the name of the function means that the function always returns a promise, so yes it is possible.
await makes JavaScript wait until the promise is resolved and it pauses when you need to work on the result of that promise.
To understand it better I recommend seeing following page https://javascript.info/async-await
You can call an async function from anywhere.
Async function returns a promise so if you call it like below you can use it as if it was a Promise.
async function example(){
return 10;
}
const returnOfAsync = example()
console.log(returnOfAsync instanceof Promise) // true
returnOfAsync.then((theReturn) => {
console.log(theReturn) // 10
})
Under the hood, an await is simply using a promise (same as a then()), the difference being that it waits for the promise to resolve before continuing execution of the code following it.
So...
Call an async function with await and you will receive the results of the async function after it has completed. Any code that follows the await will execute after the async call returns.
Call an async function without await and you will get a promise as the return value. Code following the await will execute immediately.
If the code that follows the async call requires the value returned from the async call or is dependent on something that happens in the async call, use await. If not, then don't.
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