It all started when our class began learning about Promises. In short, a promise is an object that represents awaiting for some operation to complete. There are situations where you might need promises and situations where you will not. For example, if you are looking things up in the DOM or writing to the DOM, this code executes synchronously, meaning our code will block and wait for the result on that particular line.
In the following example, we are doing a simple query for an <h2>
element in our document:
let lookUp = document.querySelector("h2")
JavaScript, while it is executing this line, will not be doing anything else. The result will be returned to lookUp
before executing the next line. So there are some (most) operations in JS where it will automatically wait for a result.
For other things, such as HTTP requests, JS will not wait for a result, therefore promises are needed to allow JS to continue executing other operations while waiting for results. The following example will only start the operation but will not give us the final result yet.
let promise = fetch("http://example.com")
Async functions help us with the situations where JS will not automatically wait for a result.
For a more complete understanding of promises, as well as this blog post, you can read up on promises here.
I happened to have stumbled upon async functions. Every time I wrote a fetch request inside a function using .then
syntax, I would get these faint-colored dots right below the function's name. Upon clicking on these dots, VSCode gives you the option to convert it to an async function, as demonstrated below:
I have since started using async functions for any HTTP request, but without knowing much of its functionality. I decided to write this blog post as I became curious about the different syntax and if there are benefits to writing async functions. This blog post is a beginner's level explanation of how async functions work. A decent amount of research was done, but as a beginner to JavaScript myself, please feel free to leave any feedback, and I will gladly update this post.
Before we get into the syntax of async/await
, we should review what a regular function that will handle asynchronous operation will look like.
The following snippet shows a fetch request using .then
syntax:
function sameFunction() {
return fetch("some_url")
.then((response) => response.json())
.then((resultFromResponse) => doSomethingWithResult(resultFromResponse));
}
When using a regular function or non-async function, the code can look somewhat messy and more difficult to understand. Also normal built-in JavaScript syntax such as if
statements and for
loops become difficult to use.
Async Functions
But what is an async
function? This is what I've gathered so far:
- These are regular functions that will begin with the keyword
async
. - Once marked with
async
, the function will only return promises now. - Once marked with
async
, theawait
keyword can be used inside the function to help with handling promises.
In one snippet,
async function someName() {
let response = await fetch("some_url");
return await response.json();
}
someName() // => Promise<pending>
Async functions with the await keyword make for much simpler handling of promises. The await keyword does exactly what you might think it would, it waits until a promise is either fulfilled or rejected to resume. Meanwhile, other functions in your code will be allowed to run. Keep in mind that the await
keyword only works inside async
functions.
Just a heads up, async
functions are not currently supported by all browsers, and you might have to use some other tools to make it more widely compatible.
Error handling
The last thing I would like to address is error handling. In regular functions, when handling errors, you need to consider errors that can happen asynchronously. Consider the following example:
function errorHandlingDemoWrong() {
try {
fetch("http://thisisjustademo.com/").then((res) => {
console.log(`status code: ${res.status}`);
});
} catch(e) {
console.log("this will never happen")
}
}
This function is trying to fetch this domain and because the domain does not exist, it will error out. Because the error occurred inside the promise chain, it will stay within the promise chain. Therefore catch
in this snippet will never be executed.
The correct way to handle this error would be to use .catch
:
function errorHandlingDemoCorrect() {
fetch("http://thisisjustademo.com/")
.then((res) => {
console.log(`status code: ${res.status}`);
})
.catch((err) => {
console.log(`an error occurred while fetching fake domain: ${err}`);
});
}
As a beginner, trying to figure out which is the right way to handle errors can be confusing.
This is another way async/await
makes writing JavaScript better. In this snippet, all error handling is done with the built-in try/catch
syntax, instead of there being two different error handling methods.
async function errorHandlingDemo() {
try {
let response = await fetch("http://thisisjustademo.com/");
console.log(`status code: ${response.status}`);
} catch (err) {
console.log(`an error occurred while fetching fake domain: ${err}`);
}
}
Handling asynchronous code can be very tricky, and async/await
makes it easier and more readable.
Top comments (0)