Let's say we have a function getPromise()
that returns a Promise that will resolve to some value in the future. The question is whether we need to declare it with the async
keyword if we want to call it either (i) using the async/await
style or (ii) using the then
clause. For example, in the same code base, some time we want to call it like this:
//Snippet 1. Call using async/await
(async() => {
try {
const result = await getPromise("a");
console.log('async/await -> ', result);
} catch (err) {
console.log(err);
}
})();
...and in some other time, like this:
//Snippet 2. Call using then clause
(() => {
getPromise("b")
.then(result => {
console.log('then -> ', result);
})
.catch(err => {
console.log(err);
});
})();
then should we declare getPromise()
like this?
//Snippet 3. Declare without async keyword
const getPromise = (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
...or like this?
//Snippet 4. Declare with async keyword
const getPromise = async (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
It turns out all of the above combinations are possible, because async/await
is still Promise-based under the hood:
If a function is declared with the
async
keyword, we can call it with theawait
keyword. So that's like snippet 4 (declaregetPromise
withasync
) and snippet 1 (calling withawait
). There should be no surprise here.But if we declare
getPromise
without theasync
keyword (snippet 3), we can still call it with theawait
keyword. The reason being isgetpromise()
returns aPromise object
. If a function returns a Promise, we can call it withawait
. So snippet 3 and snippet 1 still work together.What about calling using the
then
clause? Of course, beforeasync/await
, back when we only had Promise, we declare a function without the async keyword (snippet 3) and we call it with thethen
clause (snippet 2). That was the way to do then. It remains possible to do so now. Again no surprise here.So can we declare
getPromise()
with the async keyword (snippet 4) and call it with thethen
clause (snippet 2) ? Yes, that works too.What's not to do is the following case. The outer function which is the caller function is declared without the async keyword. The will cause a run-time error.
const getPromise = async (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
//
(() => { //no async keyword here
try {
const result = await getPromise("a");
console.log('async/await -> ', result);
} catch (err) {
console.log(err);
}
})();
6... but the following is OK (which is why I title the article async
without await
, because there's no await
anywhere in here):
const getPromise = async (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
(async() => {
getPromise("b")
.then(result => {
console.log('then -> ', result);
})
.catch(err => {
console.log(err);
});
})();
7... and lastly, we call getPromise()
without the await keyword. In this case, result
has not yet been unwrapped, so it's still only a Promise object.
const getPromise = async (s) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(s), 500);
});
}
(async() => {
try {
const result = getPromise("a"); //no await, result has not been unwrapped
console.log('async/await -> ', result);
} catch (err) {
console.log(err);
}
})();
Top comments (1)
This is a nice article Kevin.
Wanted to add little more about async function to complement with this article.
The async function automatically wraps the return value inside a promise. Whether you return a plain JS object or a Promise, it will be wrapped with a promise. Note: The compiler automatically flattens any nesting of promise for you.
In short if you are returning a promise in an async function, you can even let go of async and it will still work fine.