The complete tutorial Javascript Asynchronous. If you have read and implemented a Javascript tutorial from the beginning to part 11 (learning Javascript AJAX), you may have experienced an “undefined” error when you were sure that the code you created was correct.
For example, when Javascript makes a data request to the server using AJAX. Because access to the server is long enough, so asynchronously the Javascript runs the next code and causes the application become an error. This happens because Javascript has not received the data needed for further processing. The Asynchronous code is a big problem for developers who are familiar with the synchronous code as in the PHP programming language. But you don’t need to worry! We will discuss in full the Javascript Asynchronous functions in this article.
When I learned Javascript in the first time, I was confused because the code that was executed did not match with the writing flow (I was previously proficient in PHP). See the following example
1 2 3 | let data; setTimeout(function(){ data= 20}, 3000); console.log(data) |
What will happened ? what is the result? is data = 20 or undefined?
This is not a bug in Javascript, but an asynchronous function implemented by the Javascript. To solve the above problem, we must understand what Javascript Asynchronous is.
Table of Contents
Javascript Asynchronous
Understanding the Asynchronous concept is not a difficult thing. To be proficient in understanding Javascript asynchronous, what we must do is learn in theory and practice to gain experience. If you only run one of them, it will definitely fail. Many web developers have been unable to understand the asynchronous code in Javascript.
Understanding asynchronous program is one of the crucial things in Javascript world. This topic is often skipped when we learn the fundamental Javascript learning phase.
There are lots of asynchronous implementations in Javascript like events, timers, AJAX requests, listeners, user interactions, and much more.
Synchronous vs. Asynchronous
Synchronous and Asynchronous code is a way to distinguish the order of execution of commands in the programming code.
Synchronous code is the most frequently encountered and most easily understood. Each command is executed one by one in the order of the code.
Example:
1 2 3 | console.log('1') console.log('2') console.log('3') |
The above code example will be executed in sequence, or we call it ‘blocking.’ This has been implemented while learning Javascript.
Whereas Asynchronous code is the result of execution determined by processing time. Asynchronous execution will not block or wait for a command to finish. Javascript will not wait for the previous process to finish, asynchronously will execute the next command. This will be a problem when there is one command that depends on the results of the last execution code. This condition is called a race condition.
How do I solve the asynchronous problem in Javascript?
The solution is to implement several techniques, such as Callback and Promise.
How to resolve Javascript Asynchronous
Asynchronous Callback
Javascript callback is just a custom function. The difference between callbacks and functions, in general, is how they are executed. Functions are generally executed directly, while callbacks are executed in other functions via a parameter. That is why it’s called a Callback function. The Callback is only a concept of a programming technique.
Why can the function be used as a parameter? The function in Javascript is an object, so:
- The function can be used as a parameter
- Functions can be saved into variables
- The function has properties and methods
- The function can return a value in the form of a function
Code example:
We have a code case like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 | function p1() { console.log('p1 done') } function p2() { setTimeout( function() { console.log('p2 done') },100 ) } function p3() { console.log('p3 done') } |
If the above code is executed in sequence
1 2 3 | p1() p2() p3() |
The result:
1 2 3 | p1 done p3 done p2 done |
How to sort the results?
1 2 3 | p1 done p2 done p3 done |
We must change the code above to be as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | function p1() { console.log('p1 done') } function p2(callback) { setTimeout( function() { console.log('p2 done') callback() },100 ) } function p3() { console.log('p3 done') } p1() p2(p3) |
The concept of asynchronous Callback is just a technique to outsmart the data delays in the asynchronous process to become synchronous process. But if the application is very complex, and requires to make multiple callbacks (nested callbacks) of course, it will cause new problems. This condition is known as Callback Hell.
Callback hell is a term when making multiple callbacks within a callback (nested callbacks). Like the following example:
Drawback of using callbacks
- Unreadable code , in some cases like the pyramid code.
- Difficult to detect errors.
Because of the above shortcomings, the concept of callbacks began to be abandoned and replaced by the Javascript Promise (a new feature found in ES6).
PROMISE
The Promise is one of the features of ES6, which provides a solution handling Javascript Asynchronous activities.
Promises have 3 states:
- Pending (in the process)
- Fulfilled (successful)
- Rejected (failed)
The advantage of using Promise in the Asynchronous process is making the code more readable and better error management.
How to use Javascript promise ?
Promise is an object, to use the promise simply by calling its constructor:
1 2 3 4 5 | let promise = new Promise( (resolve,reject)=>{ //resolve("success") //reject("getting an error") }) |
Pending state occurs when a promise object created like the example above.
To set the Fulfilled and Rejected state, use the resolve() and reject() listener. Resolve() and reject() forwarded and executed by then and catch method
1 2 3 4 5 6 | .then((result)=>{ console.log(result) }) .catch((error)=>{ console.log(error) }) |
Explanation:
- If the resolve() listener executed, the result is passed to the then method (result: success)
- If the reject() listener executed, the result is given to the catch method (result: getting an error)
Request Ajax with the Fetch API
To quickly implement AJAX promises, we use the Fetch API. In the previous article, we discussed the Fetch API. Fetch is an API that was introduced since the ES6. And one of the advantages of the fetch API is that Fetch returns a promise so that it doesn’t need to create a listener (resolve and reject). See the following line of code.
1 2 3 4 5 6 7 | fetch('https://jsonplaceholder.typicode.com/posts/1') .then(function(response) { if (!response.ok) { throw Error(response.status); } return response; }).then(res => res.json()) |
Promise Chaining
Promise chaining will occur when we need data in sequence and connected to each other. As an example :
The above code is unreadable, To more comfortable the promise process, we can use the Promise all method.
Promise All
Promise all is used to simplify the chaining in promises. The Promise all method is waiting for all promises to be executed and return the result as an array.
I often use Promise All to prepare initial data before the application is ready for use. This method is quite effective and very easy to use.
Examples of using promise all
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | const getPost = () => fetch('https://jsonplaceholder.typicode.com/posts/1') const getAuthor = (id) => fetch('https://jsonplaceholder.typicode.com/users/' + id) const getComment = (id) => fetch('https://jsonplaceholder.typicode.com/users/' + id) let post = getPost() .then(function(response) { if (!response.ok) { throw Error(response.status); } return response; }).then(res => res.json()) let author = post.then(res => getAuthor(res.id)).then(function(response) { if (!response.ok) { throw Error(response.status); } return response; }).then(res => res.json()) let comment = post.then(res => getComment(res.id)).then(function(response) { if (!response.ok) { throw Error(response.status); } return response; }).then(res => res.json()) Promise.all([post,author,comment]) .then(results => { console.log(results[0]) console.log(results[1]) console.log(results[2]) }) .catch(error => console.log("error : "+ error.message)) |
Promise Race
As the name implies, Promise.race returns the results of the promise that was completed at the time of execution. As a case in point, we will take the example of a car race.
1 2 3 4 5 6 7 8 | let rider1 = new Promise(resolve => setTimeout(resolve, 50, 'Rider 1.')) let rider2 = new Promise(resolve => setTimeout(resolve, 10, 'Rider 2.')) let rider3 = new Promise(resolve => setTimeout(resolve, 60, 'Rider 3.')) let rider4 = new Promise(resolve => setTimeout(resolve, 30, 'Rider 4.')) Promise.race([rider1, rider2, rider3, rider4]) .then(val => console.log('Race finish, the winner is :', val)) .catch(err => console.log('Race stop because : ', err)); |
Conclusion
Javascript provides a solution to problems that often occur because of the asynchronous concept applied. So the issue of asynchronous in Javascript isn’t an obstacle to keep learning and exploring Javascript on every web project that we develop.
The promise is not a substitute for callbacks, because promises will always run as asynchronously while callbacks can be used both synchronous and asynchronous.
Some differences between callbacks and promises are:
- The Callback is sent via the parameter, while the promise returns the object.
- The callback is a function while the promise is an object.
- The callback can be used for several events at a time, while a promise is only for one event.
Because Javascript Promises is part of ECMAScript 6, the browser used must be the latest browser and already supports ES6 (List of browser versions that already support ES6 http://es6-features.org/).
Thus my explanation of asynchronous code in Javascript, hopefully, useful
Reference : https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous
Leave a Reply