Introduction
Do you understand the difference between synchronous and asynchronous programming? Let’s go through them first and look at several approaches to asynchronous programming in javascript.
First, let us define Synchronous Programming in JavaScript.
JavaScript is an asynchronous, single-threaded language. That is, only one operation can be engaged at any given moment.
Let’s look at an example:
In the above example, you can see that the code is run line by line, implying that javascript only does one action at a time. What if the function takes a long time to complete? We will have to wait for the function to complete its work before proceeding to the next line of execution. This is known as code blocking. To address this issue, we have several Web APIs that allow us to conduct asynchronous actions in javascript.
Let’s look into Asynchronous Programming in JavaScript now.
Asynchronous programming allows you to carry out tasks without interrupting the main thread. In asynchronous operation, you can move to another job before the previous one is finished, allowing you to handle several requests at once.
JavaScript is an asynchronous language, although it can do asynchronous activities with the aid of Web APIs, Task Queues, and Event Loops. If you’d like to learn more about Event Loop,
Let’s look at an example:
In the above example,setTimeout is used to conduct an asynchronous operation in the preceding example. setTimeout is an async Web API. As you can see, the program didn’t wait for the setTimeout in line 2 to complete the task; instead, it moved on to the next line and finally ran the callback in setTimeout.
Ways to write non-blocking code
- Callbacks
- Promises
- Async/await
Callbacks:
A callback is just a function that is sent into another function and expected to be called when the time arrives. Callbacks were historically the most common way to construct asynchronous functions in JavaScript.
Let’s look at an example:
function getData(id, callback) { console.log("API calling..."); setTimeout() => { callback({ id: id, product: 'camera' }); }, 2000); }; getData(123, (product) => { console.log("Product", product); });
In the above example, a callback is supplied to the getData method, which is invoked once the setTimeout delay has expired. However, callbacks can occasionally cause issues by causing callback hell.
Let’s take a look into callback hell.
//callback hell getUser(123, (user) => { console.log("User", user); getPosts(user.username, (posts) => { console.log(posts); getComments(posts[0], (comments) => { console.log(comments); } })
To avoid callback hell, we have promises.
Promises:
For providing the outcomes of an asynchronous computation, promises are an alternative to callbacks. They require more effort from asynchronous function implementors, but they bring significant benefits to users.
The promise function is used to create a promise:
let promise = new Promise(function(resolve, reject) { // your code resolve("resolved"); });
The callbacks resolve and refuse are supplied by JavaScript.
Promise states –
- Pending: Initial state of promise till execution is completed.
- Fulfilled: The promise-related activity was successful.
- Rejected: The promise-related activity was unsuccessful.
- Settled: Has been fulfilled or rejected.
Consumers: These are functions that can be registered using the -.then, .catch, and .finally methods and will receive the result or error. The .then the function is used for outcomes, and the .catch function is used for errors. The .finally method is called whenever the promise is resolved or refused.
But how does it solve the problem of callback hell?
The can be used to link many promises. After that, you can perform.
// Replace Callback with Promises to avoid callback hell getUser(1) .then(user => getPosts(user.username)) .then(posts => getComments(posts[0])) .then(comments => console.log("Comments", comments)) .catch(err => console.error(err.message));
Isn’t it more appealing and readable than callback hell? It’s even more concise when you use arrow functions.
Async/await:
Promise requires a particular syntax called async/await. It’s easy to understand and utilize. We only need to add the async keyword before the function, and the function will return a promise. Then we use await before the promise and attach the value received to a variable inside the function.
Let’s look at another example from promise chaining.
async function displayComments() { try { const user = await getUser(123); const posts = await getPosts(user.username); const comments = await getComments(posts[0]); console.log(comments); } catch (err) { console.error(err.message); } } displayComments();
Promise .then is replaced with async/await, which is a more elegant syntax for retrieving the promise outcome. It’s also simpler to read and write. Because the .catch method isn’t available in async/await, we utilize try-catch to manage problems.
Note that await only works within async functions.
Final thoughts:
We briefly discussed the following topics:
- Synchronous and asynchronous programming
- Callbacks and callback hell
- Promises and async/await
Thank you for taking the time to read this!!
If you enjoyed it, please leave some feedback. If you have anything to say about the topic or would want to provide feedback, please do so in the comments section.