In the first part, we've reviewed a mechanism of Promises
, introduced as a part of ECMAScript 2015 (and polyfilled years before).
A year later, with ECMAScript 2016 and asynchronous functions, we’ve got an opportunity to write asynchronous code in a more familiar, synchronous-like way, thanks to await
keyword. This changed an approach of handling asynchronous actions once again, and still, not everyone got used to it.
Do you remember I mentioned a so-called capsule
while talking about Promises
? It holds a value once Promise
is created and allows us to process a result only inside of it. So, async function
is the representation of that capsule. Every function declared as async
returns a Promise
, no matter whether you return it or not. If you don't, Javascript will wrap a return value with a Promise
by itself.
async function test() {
return 'OK'; // Promise {<resolved>: "OK"}
}
async function fail() {
throw new Error('random'); // Promise {<rejected>: Error: random
}
Once defined, it can be called differently, by using await
keyword.
async function testWrapper() {
const response = await test();
console.log(response);
}
Straight away async/await
looks as syntactic sugar for a Promise. And it definitely is. This syntax brings us an opportunity to work with asynchronous code as it'd be a regular synchronous code. In addition to this, new syntax opens the following opportunities:
try/catch
syntax;Promise
(extract a value from a capsule
).Due to syntax change, it is important to understand on how to handle exceptions correctly. Let's review and example:
const request = async () => {
const response = await fetch('https://alxblsk.com/rss.xml');
const data = await response.text();
const xmlData = (new window.DOMParser()).parseFromString(data, "text/xml");
return from(xmlData.getElementsByTagName('item'));
}
const render = async () => {
let tree;
try {
tree = await request();
} catch (ex) {
console.warn(ex);
tree = [];
}
return tree;
}
// call render() here
Notice we perform two asynchronous actions here: first requests an XML from a server, while the second one parses a body of a response.
async
and require await
before a call;But here is the thing: it's not necessary to handle those errors inside of request
function.
Promise.reject()
and can be handled on a top-level;You may notice that with those two separate functions code may look a bit verbose. Indeed. However, other factors become important here: readability, supportability, and testability. In the era of high speeds and smart obfuscation mechanisms, the latter may be much more important than 5 saved lines of code.
async
as well.async
function can be called only inside of another async
function.await
can be used only inside of async
function as well.try/catch
on a top-level.