Introduction
Asynchronous JavaScript can be a daunting concept to learn. However, it is a essential tool in the toolkit of a JavaScript programmer. It can be used to improve the user experience. We'll understand more about the importance of Asynchronous code as we go along further in the article.
Topics that we'll look into :
Part 1
- JavaScript Call Stack
- What Does Asynchronous Mean
- AJAX
- APIs and WebAPIs
- CallBacks
Part 2
- Promises
- Async and Await
- Making Http Request
- API Project
Prerequisites
Basic knowledge of JavaScript is required.
Note
The goal here is to have an understanding about how all the puzzle pieces fit into the bigger picture.
Let us begin by understanding how JavaScript works .
JavaScript call stack
JavaScript is a single threaded language. It means that JavaScript can only run one piece of code at a time. It does so using something called as the Call Stack.
Call stack is how the JavaScript engine keeps track of its place in the script and also manages the different function calls. Stack is a data structure which operates on the LIFO(Last in first out) principle .
Here we can see "3" comes last in the stack so it will be the first one to be executed and after it is executed it will be popped off the stack.
We can visualize this using a tool called loupe
Here is an example :
console.log("start");
console.log("End");
- When we run this code the first log goes into the call stack.
- After execution, it is popped off the call stack
- Then the second log is pushed into the stack.
- After execution it is popped off and the program ends
This is what we call synchronous flow (One after the other).
Whenever we search anything on google, we see that the page refreshes and waits for the response. This is the default synchronous behavior. The programs waits for the response.
What does Asynchronous mean
Let us understand Asynchronous with an example :-
Whenever we are searching something on the YouTube search bar, we can see suggestions as soon as we start typing .
This basically means that requests are being made to the server behind the scenes to get the suggestion after each letter you type.
This however, doesn't block the UI of the website improving the experience of the user. This is called as an Asynchronous request.
Let us take an example of the setTimeout function :
console.log("start")
setTimeout(function(){
console.log("middle")
},1000)
console.log("end")
What do you think is the output of this code ?
start
middle
end
Since JavaScript as we saw is single threaded, the above output should be correct right? But the output is different from what we might expect .
This is the actual output of the script.
start
end
middle
It seems JavaScript moved ahead by printing start and end first, then the setTimeout ran asynchronously, waited for 1sec and returned the result. So why does this work? How can JavaScript hold the variable and continue executing the code simultaneously?
So the thing is the setTimeout is actually not part of javascript. It is what we call a browser API . We will understand more about APIs in the next section but hang with me for a bit.
Web Browser APIs are like super powers provided to us by the browser. For example it can do something like holding a value with setTimeout for a specific amount of time and then returning the value.
working of the setTimeout function
- Line one is pushed into the stack and 'start' is printed in the console.
- setTimeout is pushed into the stack.
- The call stack pops the function then asks the browser API that "Hey Browser ! Hold the value in the function for 1 sec and remind me to run it after the time is up"
- The call stack moves ahead with the next line of code and prints 'end' in the console
After the time is completed the browser API then tell the call stack that "Hey remember the function I was holding, you can execute it now".
Finally "middle" is printed in the console.
Asynchronous however is not limited to setTimeout function.
why do we need asynchronous code
- Although some requests may not take much time, some requests like getting data from a database or an API may take a few seconds .
- If we make these requests synchronously it will block the UI while getting the data, since JavaScript can perform only one task at a time. This will degrade the user experience.
Some things that may need an Asynchronous request include :
- Getting data from a database.
- Verify user while login and signup.
- Getting JSON data from an external Web API.
AJAX
- AJAX stands for Asynchronous JavaScript and XML.
- AJAX is not a technology or tool, it is a concept .
- It is just a terminology used for describing asynchronous code.
- When we asynchronously exchange data with the server it is called as an AJAX request.
- We can also update the page without reloading the web page.
So what does the xml part in ajax means?
- When we talk about exchanging data with different servers running different technology, there has to be a single format of data that can be understood by all the servers .
- XML and JSON provide us these interfaces which let us transfer data in a format understood by all.
XML
- XML stands for eXtensible Markup Language .
- It is similar to html in the sense that it also uses tags like HTML.
- However the key difference is that, HTML is used for displaying data and XML is used for storing and transferring the data.
SYNTAX
<note>
<date>2015-09-01</date>
<hour>08:30</hour>
<to>Tove</to>
<from>Jani</from>
<body>This is a reminder</body>
</note>
JSON
JSON stands for JavaScript Object Notation. It also is a format for transferring data. It is an alternative to xml. JSON is really easy to read and understand. Even though it looks like JavaScript objects JSON can be used independent of JavaScript to transfer data . Many programming languages have ability to parse and read JSON.
The two primary parts that make up JSON are keys and values. Together they make a key/value pair.
- Key : A key is always a string enclosed in quotation marks.
- Value : A value can be a string, number, Boolean expression, array, or object.
JSON is a more popular format than XML.
Anyone who is familiar with JavaScript objects will understand JSON very easily.
modern APIs mostly use JSON to transfer and store data.
{
"squadName": "Super hero squad",
"homeTown": "Metro City",
"formed": 2016,
"secretBase": "Super tower",
"active": true,
"members": [
{
"name": "Molecule Man",
"age": 29,
"secretIdentity": "Dan Jukes",
},
{
"name": "Madame Uppercut",
"age": 39,
"secretIdentity": "Jane Wilson",
}
]
}
What is an API?
API is the acronym for Application Programming Interface.
API is an interface which has a set of functions that allow programmers to access specific features or data of an application, operating system or other services.
Web APIs
Often when we talk about APIs in terms of web development the APIs refer to 'Web APIs'.
Web API as the name suggests, is an API over the web which can be accessed using HTTP protocol.
Typically when we make a request to a webpage we get all sorts of data like html, CSS, JavaScript. On the contrary when we make asynchronous request through JavaScript we might want a particular part of the data.
Web API takes requests from the different type of client devices like mobile, laptop, etc. and sends them to the web-server to process it and returns the desired data to the client.
For example: Twitter's APIs provide access to read and write data using which we can integrate twitter's capabilities into our own application. We could for instance, get data about the users tweets and use it in our own application.
The data given by the API can be anything for example : images, JSON objects etc.
- We'll understand these APIs HTTP requests in detail a little later but stick with me for a while .
- API requests are like any other HTTP request you make to different websites in the search bar like google, Facebook etc. but response from the API is without the unwanted data (html, css etc.).
Let's take an example to understand this better
This is a Pokémon API .It returns an image of a Pokémon when we send it a request. we have to replace the id with the id of the Pokémon we want . 1 is Bulbasaur etc.
This is what we get when we send a request to https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/1.png .
You all can also give it a try! Just put the above link in the browser and you'll get back the image. You can also try changing the id to see what different results you get.
It is just like any other http request but only with the data(image).
Query Strings
In the URL of the API we had to replace the id of the image according to what we want.
That is basically a query string. It request the data according to the value we pass in the query string .
Let take another example
This is another API that we will be using later.
In the url, ?q=:query
is called as the query string and :query
is a variable. The response changes according to the value of the query variable.
With the Pokémon API, we took a simple example which returns the data instantaneously. However, some actions like retrieval of information from a database may take some more time or might even get rejected. Thus we have to take into consideration handling the errors that we might get.
We will discuss the various ways to make async request in a few sections.
But before that we'll have to see how to handle the failure of the asynchronous request.
Callback function
Definition
A callback function is a function passed into another function as an argument, which is then invoked inside the outer function to complete some kind of routine or action.
Whatttttt!!!!
Here is an example :
const success = ()=>(
console.log("success")
)
const fail = ()=>(
console.log("fail")
)
const check = (success,fail)=>{
const a = 2
if(a == 2){
success()
}else{
fail()
}}
check(success,fail)
- Let us assume there are 2 functions
success
andfail
- We pass these two function as arguments to a third function called
check
. - When
check
is executed it calls thesuccess
function if the variable 'a' is equal to 2 else it calls thefail
function. - The
success
andfail
function are called as callback functions since they are passed as arguments and invoked within acheck
function after something happens.
Alright! Let's bring out our friendly neighborhood setTimeout
function again.
- As we know there are 2 parameters to the setTimeout function . First is a function and second is a delay .
setTimeout(someFunction,delay)
Let us make a function and pass it to setTimeout
const message = function() {
console.log("I Have been waiting for 3 sec !!!");
}
setTimeout(message,3000)
The setTimeout
which is like an outer function calls the "message" function which is an argument. Here, message
function is a callback function.
- Let us see how the setTimeout is defined.
setTimeout(message,3000){
/*
some code which will hold the value for 3 secs
*/
message()
}
- We see that the function(message) which was passed to
setTimeout
as an argument was called within setTimeout.
Passing callbacks may not be the best way
Suppose we want to write a script in which we have to execute multiple async operations but only after the previous operation completes . In this scenario callbacks may not be our best option. Let us see why.
Let's say we are writing a function to change the background colour of the body to the different colors of the rainbow. However, each colour should appear 1 sec apart from each other. For example red appears after 1 sec, orange appears after 2, yellow appears after 3 and so on.
- We understand that we can use the setTimeout to delay the colours. However, we cannot just use them independent of each other, since we will have to calculate the delay.
/* assume that red , orange , yellow are
the functions to change the bg color to the respective colour.*/
setTimeout(red,1000);
setTimeout(orange,2000);
setTimeout(yellow,3000);
- We could pass a callback to a function which basically runs the next setTimeout only after the previous
setTimeout
finishes. - It'll look something like this :
const delayedColorChange = (newColor, delay, doNext) => {
setTimeout(() => {
document.body.style.backgroundColor = newColor;
doNext();
}, delay)
}
- So, how will we go about calling this function?
- let's say we want to change the colour to red then to orange.
- The "doNext" argument will contain a callback that again calls the delayedColorChange function but now with the colour as orange. something like this
delayedColorChanged("red",1000,()={
delayedColorChanged("orange",1000,()=>{
//This function will be empty since we want to end the
//color change
});
})
- Now lets say we want to change the colour to yellow after orange.
delayedColorChanged("red",1000,()={
delayedColorChanged("orange",1000,()=>{
delayedColorChanged("yellow",1000,()=>{
//This function will be empty since we want to end the
//color change
});
});
})
- Let's now make a full rainbow.
delayedColorChange('red', 1000, () => {
delayedColorChange('orange', 1000, () => {
delayedColorChange('yellow', 1000, () => {
delayedColorChange('green', 1000, () => {
delayedColorChange('blue', 1000, () => {
delayedColorChange('indigo', 1000, () => {
delayedColorChange('violet', 1000, () => {
//This function will be empty since
//we want to end the
//color change
})
})
})
})
})
})
});
- It gets a little confusing as we go on nesting more callbacks.
- Even though we just used one callback function here it got pretty crazy. APIs or any kind of async request will have two of them, success and failure. In that case, there will be a lot of nesting .
- Let us assume
fakeRequestCallback(url,success,failure)
is a fake function that will request the URL for data. -
success
andfailure
are two callback functions. - If no error,
success
is called, else thefailure
is called. - Here is what happens when we make requests to multiple pages but only after the previous request is successful, similar to the rainbow function.
fakeRequestCallback('books.com/page1',
function (response) {
console.log(response)
fakeRequestCallback('books.com/page2',
function (response) {
console.log(response)
fakeRequestCallback('books.com/page3',
function (response) {
console.log(response)
},
function (err) {
console.log("ERROR (3rd req)!!!", err)
})
},
function (err) {
console.log("ERROR (2nd req)!!!", err)
})
}, function (err) {
console.log("ERROR!!!", err)
})
Welcome to callback hell .
If there are multiple async operations to be performed and we try to use our good-old callbacks , we’ll find ourselves in the callback hell .
Let us see if there is a better way in part 2.
Top comments (4)
It's like you've lived with JS your entire life. Splendid work man !!
Loved those gifs,real time examples ... everything in fact.
Thank you !!😄
Very informative!
Explained everything in very simple manner so that anyone can understand it. Keep posting more advanced articles. Thanks a lot for sharing.
Waiting for the Part 2 !!
Very well explained 🔥