Step by step guide to async programming in Javascript
Async programming in modern Javascript
Asynchronous programming is a technique that lets your code continue running while it waits for external events, like a user's click or data coming in from the internet. This is different from how code runs in some other languages, where things happen strictly one after the other.
Understanding asynchronous programming can be tricky if you're used to languages like Java or C. That's why it's important to grasp this concept for working with JavaScript, the language that runs in web browsers.
In the past, JavaScript relied on 'callbacks' for asynchronous coding. Callbacks can make your code complex and hard to follow. Fortunately, modern JavaScript (ES6 and beyond) provides improved ways to manage asynchronous operations, making your code cleaner and easier to understand.
Table of contents
Understanding Asynchronous Code
Asynchronous code typically involves three key components:
- The Trigger: An event or action that occurs at an unpredictable time (e.g., a network request, user input).
- The Success Handler: Code executed when the trigger resolves successfully.
- The Error Handler: Code executed if the trigger results in an error.
See an example:
Above code uses something called "Promises" which even though not clearly visible in the code itself, they are what actually being returned.
Promise is an object is returned when an async operation like Fetch is performed. A promise can be seen as an object that you can pass around as result of the operation even if the result is actually unknown. At anytime you want to check if the promise has completed (called 'resolved' ) you can query this object.
The code fetch('https://api.github.com/users/tanvin') actually returns a promise. Each promise supports two methods.
- Then
This method takes a callback that executes if the async operation executed successfully.
- Catch
This method takes a callback that executes if the async operation ended up in error.
The advantage of this approach is that you can write and read code without worrying too much about callbacks.
To give you an example:
Same code when written without promises would look something like this:
The second code is more complex and harder to read and maintain. It also violates separation of concerns as getUserInfo here not only fetches user infor but also determines what to do with that content. Not to mention displayUserName and displayUserRepositories are now more complicated as they have to handle the success and error case differently.
This is even more complicated when you have say multiple operations that need to be chained. In such cases normal callback based approach quickly becomes "callback hell".
On other hand promises provide a very clean way of doing this.
Async and Await in Javascript
Above promises based approach does make writing and reading code simpler and solves a lot of painpoints of older javascript standards. However, human beings are often not very good at thinking in terms of promises. It is still somewhat confusing.
Human beings think in following manner.
- Do something
- If that thing is done then do something else.
- If there was an error do something entirely different.
This is a very intuitive step by step thinking.
For example say when user visits a page, you want to tell the server the page was visited and ask it to update a page counter. Then update the counter accordingly on the page.
Whenever promises are involved, at some point you will have to use the methods "then" and "catch". Wherever they are used, they make it harder to read the code.
Javascript provides a shortcut to write this code.
Above code is exactly same as the code above it. Except that the async and await keywords have simplied how the code is written. It is just syntatic sugar around promises.
updateAndDisplayPageCounter returns a promise just like earlier.
The advantage of this syntax is that it allows you to use a more familiar syntax instead of using "then" and "catch" as long as the method is marked as "async".
Conclusion
JavaScript (ES6 and beyond) offers promises, along with the 'async' and 'await' syntax, to streamline asynchronous code. These features significantly improve readability, maintainability, and the ability to chain operations logically. Understanding these concepts is essential for modern JavaScript developers who want to write clean, efficient asynchronous code.