Is await mandatory to use with async method in JavaScript - javascript

I was discussing with someone else about the use of async/await in JavaScript and we didn't agree.
Personally, I only use await when I need to wait for the async method to be finished. If I don't need it to finish to continue, I don't.
E.g.:
async myAsyncMethod() {
axios.get(`/foo`)
.then((response) => {
this.foo = response.data;
}).catch (exception) {
//do something with exception
this.foo = null;
};
}
If I need the data right away, I call:
await myAsyncMethod();
If I don't, I do:
myAsyncMethod();
Is it not correct to do this last one? The other person maintained that I should not. If so, would it be possible to explain to me why.
I've edited the myAsyncMethod() to be more precise. So my questions implies that that I catch errors and that I know that 'foo' is either null either field with data at some point... The point is that I don't need those data right away and I've got other things to do that don't require it.

An async function without an await expression will run synchronously.
The await expression causes async function execution to pause until a Promise is settled (that is, fulfilled or rejected), and to resume execution of the async function after fulfillment.
So, in your case, the myAsyncMethod will return an unsettled promise unless you await it.
References:
Async function
Await operator

Related

should I add .then() after the async function call even when i don't need anything back from that function? [duplicate]

I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();

What is the difference between using and omitting keyword "await" in these two code blocks?

I'm following along an MDN article on async/await, and I understand the purpose of using the async keyword before functions, but I'm a little more confused about the await keyword. I've read up on on "await" as a result, and I get the general concept, but I'm still unsure when it comes to examples. For instance, here is a trivial piece of code (as shown in the MDN article) using async/await.
async function hello() {
return greeting = await Promise.resolve("Hello");
};
hello().then(value => console.log(value));
As you might expect, this logs "Hello" to the console. But even if we omit "await", it has the exact same output.
async function hello() {
return greeting = Promise.resolve("Hello"); // without await
};
hello().then(value => console.log(value));
Can someone help me understand exactly what the await keyword before Promise.resolve is doing? Why is the output the same even if it's omitted? Thanks.
In up-to-date JavaScript engines, there's no difference, but only because the return await somePromise is at the top level of the function code. If it were within a control block (for instance, try/catch), it would matter.
This is a recent-ish change. Until ES2020 the return await version would have introduced an extra async "tick" into the process. But that was optimized out in a "normative change" (rather than proposal) in ES2020 when the promise being awaited is a native promise. (For a non-native thenable, there's still a small difference.)
For the avoidance of doubt, there's an important difference between:
async function example() {
try {
return await somethingReturningAPromise();
} catch (e) {
// ...do something with the error/rejection...
}
}
and
async function example() {
try {
return somethingReturningAPromise();
} catch (e) {
// ...do something with the error/rejection...
}
}
In the former, a rejection of the promise from somethingReturningAPromise() goes to the catch block, because it's been awaited. In the latter, it doesn't, because you've just returned the promise, which resolves the promise from the async function to the promise somethingReturningAPromise() returns, without subjecting it to the catch.
But in your example, where it's not in any control structure, the await is largely a matter of style at this point.
Keep in mind that async/await is just a fancy API for working with promises.
An async function always and implicitly returns a promise (as soon as the first await or return statement is reached) that will be resolved when the function code itself finally reaches its end. The resolved promise value will be equal to the function's returned value.
async allows you to use await inside of the asynchronous scope. Await only makes sense when preceding a promise (could be another async function call, a promise created in place with new Promise(), etc.). Using await before non promise values will do no harm though.
await indicates, just that, wait. It tells the engine to 'stop' code execution on that scope and to resume it whenever the promise is fulfilled. await will then give you or 'return' the promise resolved value.
Just to give you some practical examples:
Using your first code:
async function hello() {
const greeting = await Promise.resolve("Hello"); // HERE I CAN USE await BECAUSE I'M INSIDE AN async SCOPE.
console.log('I will be printed after above promise is resolved.');
return greeting;
};
hello().then(value => console.log(value));
Using your second code, async could be completely removed:
function hello() {
return Promise.resolve("Hello");
};
hello().then(value => console.log(value));
Please let me know if there is any doubt.

Should we wait for promises to return before responding to web request? [duplicate]

I would like to run this code with babel:
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
inside an async function without await the first line. is this OK?
how else can I run something that I don't care?
Can I just fire the non-promisified function del('key',null) without a callback?
Yes, you can do that, and it will run the two asynchronous functions in parallel. You've just created a promise and thrown it away.
However, this means that when the promise is rejected you won't notice. You'll just get an unhandledRejection eventually which will crash your process if not handled.
Is this OK? How can I run something that I don't care?
Probably it's not OK. If you truly wouldn't care, you hadn't run it in the first place. So you should be clear and explicit what you care about (and what not):
do you want to wait? (for side effects)
do you need the result?
do you want to catch exceptions?
If you only want to wait and don't care for the result value, you can easily throw away the result:
void (await someAsyncFunction()); // or omit the void keyword,
// doesn't make a difference in an expression statement
If you don't care about exceptions, you can ignore them using
… someAsyncFunction().catch(function ignore() {}) …
You can throw that away, await it, do anything with it.
If you want the result, you have to await it. If you care about exceptions, but don't really want to wait, you may want to execute it in parallel with the following functions:
var [_, res] = await Promise.all([
someAsyncFunction(), // result is ignored, exceptions aren't
someOtherAsyncFunction()
]);
return res;
inside an async function without await the first line. is this OK?
Yes, there are cases where you'd want to do this which are perfectly reasonable. Especially where you don't care about the result - one example is an analytics tracking operation that should not interfere with business critical code.
how else can I run something that I don't care?
In many ways, however simply calling the promise function works. Your del without a callback would probably work in this case but some functions don't guard against not passing callbacks, so you can pass an empty function instead (.del('key', () => {})).
You do want to however make sure that you know about it failing, even if you don't want to disrupt the operation of code - so please consider adding a process.on("unhandledRejection', event handler to explicitly ignore these particular exceptions or suppress them via:
redisClient.delAsync('key').catch(()=>{});
Or preferably, something like:
redisClient.delAsync('key').catch(logErr);
From all the research I've made so far, I think it's fine to do it, as long as you guarantee that the function you are not awaiting for guarantees a way to handle its own errors in case that happens. For example, a try-catch wrapping the whole function body, like you see in the following snippet for the asyncFunction.
It doesn't matter if the function throws synchronously or asynchronously. It guarantees the your mainFunction will complete no matter what. That's the key point here.
If you don't guarantee that, you have to risks:
If it throws synchronously, your main function will not complete.
If it throws asynchronously, you'll get an unhandled excepction
// THIS IS SOME API CALL YOU DON'T WANT TO WAIT FOR
const mockAPI = () => {
console.log("From mockAPI");
return new Promise((resolve,reject) => {
setTimeout(() => reject("LATE THROW: API ERROR"), 500);
});
};
// THIS IS THE SOME ASYNC FUNCTION YOU CALL BUT NOT AWAIT FOR
const asyncFunction = async (syncThrow) => {
try {
console.log("Async function START");
if (syncThrow) throw new Error("EARLY THROW");
await mockAPI();
console.log("Async function DONE");
}
catch(err) {
console.log("From async function catch");
console.log(err.message || err);
return;
}
};
// THIS IS YOUR MAIN FUNCTION
const mainFunction = async (syncThrow) => {
try {
console.clear();
console.log("Main function START");
asyncFunction(syncThrow);
console.log("Main function DONE <<< THAT'S THE IMPORTANT PART");
}
catch(err) {
console.log("THIS WILL NEVER HAPPEN");
console.log(err);
}
};
<div>
<button onClick="mainFunction(true)">Sync throw</button>
<button onClick="mainFunction(false)">Async throw</button>
</div>
Not in Node.js.
Node does not wait for ever-pending Promises. If other tasks are already completed and there is nothing left in the event loop, the Node process will be terminated even though there exists pending promise.
For the following script, if someOtherAsyncFunction() get resolved in 5 seconds, but redisClientAsync.delAsync('key') takes 10 seconds to execute, the Node process will be terminated after 5 seconds in theory, before the first line is resolved.
async function doSomething() {
redisClientAsync.delAsync('key');
return await someOtherAsyncFunction();
}
await doSomething();

What is the meaning of the `async` keyword?

I have been reading up on async/await in Node.js. I have learnt that the await keyword waits for a promise to be resolved, or throws an exception if it was rejected.
I have also learnt that every function that wants to use await needs to be marked async. However, what does it mean for a function to be marked async?
All the resources and blog posts I was able to find seem to explain await in great detail, but ignore the concept of an async function, or briefly gloss over it. For instance, this author puts it like this:
This makes the function return a Promise implicitly.
What does the async keyword really do? What does it mean for a function to implicitly return a Promise? What are the side effects other than being able to use await?
Alright, so from the answers I have received so far it's clear that it simply wraps the function's return value into a Promise, much like Promise.then would. That just leaves a new question though. Why does a function that uses await need to be async and thus return a Promise?
No matter what you actually return from your function, your async function will still return a Promise. If you return a Number, it actually returns a Promise that resolves to the Number your originally returned. This allows you to write synchronous "looking" code.
Rather than having to write out this:
function foo(){
return Promise.resolve("foo");
}
You can just write this:
async function foo(){
return "foo";
}
and foo() will automagically return a Promise that resolves to "foo".
In response to you comment:
Does it behave like Promise.then in the sense that if you already
return a Promise, it won't wrap it again?
await will peel the Promise until it gets to a value:
async function foo() {
return Promise.resolve(Promise.resolve(true));
}
async function bar() {
return true;
}
(async function () {
let tmp;
tmp = await foo();
console.log(tmp);
tmp = await bar();
console.log(tmp);
console.log("Done");
}());
/*
Prints:
true
true
Done
*/
Why is async needed?
Paraphrasing from #KevinB's comment.
await, just like yield in a generator, pauses the execution of that context until the Promise it's waiting on is no longer pending. This cannot happen in normal functions.
If a function is async but does not contain an await, the promise will be resolved immediately, and any callbacks will be ran on the next tick.
What does async do?
async is syntactic sugar for making your method chain Promise objects.
Take the following method for example:
async function myFunction(a)
{
if (a == 10)
{
await otherFunction();
}
return 10;
}
The JavaScript runtime you use might make more optimized code, but in its simplest it will be something along the lines:
function myFunction(a)
{
if (a === 10)
{
return otherFunction()
.then(() => myFunction_continuation());
}
else
{
return myFunction_continuation();
}
function myFunction_continuation()
{
return Promise.resolve(10);
}
}
For documentation on the Promise type I recommend checking out the Mozilla Developer Network page about the Promise type .
Why do you need to mark it async? Why not just use await?
Because your method needs to be split up into multiple "parts" for it to be able to have code execute after the method being awaited on. The example above has a single continuation, but there could be multiple.
The designers of JavaScript want to make it visible to the developer that the runtime is doing this "magic". But maybe the most important reason is that they don't want to break existing code using await as a variable name. They do this by making await a "contextual keyword". A "contextual keyword" is only a keyword in specific scenarios, in this case: when used inside a method marked as async:
function ABC()
{
var await = 10;
}
The above compiles. But if I add the async keyword to the function declaration it no longer does and throws an Uncaught SyntaxError: Unexpected reserved word.
Asynchronous Task Running
The Basic idea is to use a function marked with async instead of a generator and use await instead of yield when calling a function, such as:
(async function() {
let contents = await readFile('config.json');
doSomethingWith(contents);
console.log('Done');
});
The Async Keyword before function indicates that the function is meant to run in an asynchronous manner. The await keyword signals that the function call to readFile('config.json') should return a promise, and if it doesn't, the response should be wrapped in a promise.
The end result is that you can write asynchronous code as if it were synchronous without overhead of managing an iterator-based state machine.
Understanding ECMACSCRIPT 6 by Nicholas c. Zakas

Is it legitimate to omit the 'await' in some cases?

I am using async/await in several places in my code.
For example, if I have this function:
async function func(x) {
...
return y;
}
Then I always call it as follows:
async function func2(x) {
let y = await func(x);
...
}
I have noticed that in some cases, I can omit the await and the program will still run correctly, so I cannot quite figure out when I must use await and when I can drop it.
I have concluded that it is "legitimate" to drop the await only directly within a return statement.
For example:
async function func2(x) {
...
return func(x); // instead of return await func(x);
}
Is this conclusion correct, or else, what am I missing here?
EDIT:
A small (but important) notion that has not been mentioned in any of the answers below, which I have just encountered and realized:
It is NOT "legitimate" to drop the await within a return statement, if the called function may throw an exception, and that statement is therefore executed inside a try block.
For example, removing the await in the code below is "dangerous":
async function func1() {
try {
return await func2();
}
catch (error) {
return something_else;
}
}
The reason is that the try block completes without an exception, and the Promise object returns "normally". In any function which calls the outer function, however, when this Promise object is "executed", the actual error will occur and an exception will be thrown. This exception will be handled successfully in the outer function only if await is used. Otherwise, that responsibility goes up, where an additional try/catch clause will be required.
If func is an async function then calling it with and without await has different effects.
async function func(x) {
return x;
}
let y = await func(1); // 1
let z = func(1) // Promise (resolves to 1)
It is always legitimate to omit the await keyword, but means you will have to handle the promises in the traditional style instead (defeating the point of async/await in the first place).
func(1).then(z => /* use z here */)
If your return statements use await then you can be sure that if it throws an error it can be caught inside your function, rather than by the code that calls it.
await just lets you to treat promises as values, when used inside an async function.
On the other hand, async works quite the opposite, it tags the function to return a promise, even if it happens to return a real, synchronous value (which sounds quite strange for an async function... but happens often when you have a function that either return a value or a promise based on conditions).
So:
I have concluded that it is "legitimate" to drop the await only directly within a return statement.
In the last return statement of an async function, you just are returning a Promise, either you are return actually a directly a promise, a real value, or a Promise-as-value with the await keyword.
So, is pretty redundant to use await in the return statement: you're using await to cast the promise to a value -in the context of that async execution-, but then the async tag of the function will treat that value as a promise.
So yes, is always safe to drop await in the last return statement.
PS: actually, await expects any thenable, i.e. an object that has a then property: it doesn't need a fully spec compliant Promise to work, afaik.
PS2: of course, you can always drop await keyword when invoking synchronous functions: it isn't needed at all.
An async function always returns a Promise.
So please keep in mind that these writing of an async function are all the same:
// tedious, sometimes necessary
async function foo() {
return new Promise((resolve) => resolve(1)))
}
// shorter
async function foo() {
return Promise.resolve(1)
}
// very concise but calling `foo` still returns a promise
async function foo() {
return 1 // yes this is still a promise
}
You call all of them via foo().then(console.log) to print 1. Or you could call them from another async function via await foo(), yet it is not always necessary to await the promise right away.
As pointed out by other answers, await resolves the promise to the actual return value statement on success (or will throw an exception on fail), whereas without await you get back only a pending promise instance that either might succeed or fail in the future.
Another use case of omitting (i.e.: being careful about its usage) await is that you might most likely want to parallelize tasks when writing async code. await can hinder you here.
Compare these two examples within the scope of an async function:
async function func() {
const foo = await tediousLongProcess("foo") // wait until promise is resolved
const bar = await tediousLongProcess("bar") // wait until promise is resolved
return Promise.resolve([foo, bar]) // Now the Promise of `func` is marked as a success. Keep in mind that `Promise.resolve` is not necessary, `return [foo, bar]` suffices. And also keep in mind that an async function *always* returns a Promise.
}
with:
async function func() {
promises = [tediousLongProcess("foo"), tediousLongProcess("bar")]
return Promise.all(promises) // returns a promise on success you have its values in order
}
The first will take significantly longer than the last one, as each await as the name implies will stop the execution until you resolve the first promise, then the next one.
In the second example, the Promise.all the promises will be pending at the same time and resolve whatever order, the result will then be ordered once all the promises have been resolved.
(The Bluebird promise library also provides a nice Bluebird.map function where you can define the concurrency as Promise.all might cripple your system.)
I only use await when want to work on the actual values. If I want just a promise, there is no need to await its values, and in some cases it may actually harm your code's performance.
I got a good answer above, here is just another explanation which has occurred to me.
Suppose I have this:
async function func(x) {
...
return y;
}
async function func2(x) {
...
return await func(x);
}
async function func3(x) {
let y = await func2(x);
...
}
The reason why I can safely remove the await in the return statement on func2, is that I already have an await when I call func2 in func3.
So essentially, in func3 above I have something like await await func(x).
Of course, there is no harm in that, so it's probably better to keep the await in order to ensure desired operation.

Categories