Asynchronous JavaScript
Javascript code runs on a single thread and hence should be synchronous
in nature. Synchronous code waits for one action to complete before moving
on to next task. But even though JS is considered as single threaded
we are able to perform tasks parallely HOW?
var test = readSync(file_loc);
console.log(test);
var test2 = readSync(file_loc2);
console.log(test2);
This task is done synchronously as first file is fetched and test is logged then
next file is fetched and logged. What if the file1 is huge file and lets say
take 10sec to be fetched then this become blocking i/o and decreases UX.
So to get rid of this situation we can perform the same task asynchronously
readAsync(file_loc,(test)=>{
console.log(test);
});
readAsync(file_loc2,(test2)=>{
console.log(test2);
});
In this case file1 and file2 both are fetched parallely and file which is fetched first is being logged first this becomes non-blocking code and takes lesser time to execute.
What is Asynchronous JavaScript?
Asynchronous JS basically means, codes which starts now, and finishes at a later point in time and can perform any other task simultaneously in the time.
Fetching data from a json file using AJAX request:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Ajax</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
window.onload = function() {
$.get("zap.json", function (data) {
console.log(data);
});
console.log("later");
};
</script>
</head>
<body>
</body>
</html>
output
Here later
is printed first while the data is being fetched from json file and
as soon as the data is fetched then the callback function is fired and data
is being printed.
AJAX : Asynchronous JavaScript And XML
Communicate with server by making http request and retrieves data from server
without reloading the page which we can further use that data in our code. XML refers to as
the data which we try to fetch , we can also use JSON instead of XML.
Consider google maps as example, we are able to fetch different locations without
refreshing the page,thats how AJAX is advantageous.
How AsyncJS works?
- Callback
- Promises
- Generators
Callback function
A callback function, also known as a higher-order function, is a function
that is passed to another function as a parameter, and the callback function is called
inside the otherFunction. A callback function is essentially a pattern,
and therefore, the use of a callback function is also known as a
callback pattern.
Callback implemented using jQuery
window.onload = function() {
$.ajax({
type:"GET",
url:"zap.json",
success:function(data){
console.log(data);
$.ajax({
type:"GET",
url:"test.json",
success:function(data){
console.log(data);
$.ajax({
type:"GET",
url:"test2.json",
success:function(data){
console.log(data);
},
error:function (err) {
console.log(err);
}
})
},
error:function (err) {
console.log(err);
}
})
},
error:function (err) {
console.log(err);
}
})
};
Here function inside a function is being called only if the previous function executes without any error this is called callback functions. See the pyramid shape and all the
})
at the end? Eek! This is affectionately known as callback hell. 😨
Output
Callback hell can be resolved by Modularizing our code and handling every single error. Above code be rewritten by resolving callback hell as:
window.onload = function() {
function checkerror(err) {
console.log(err);
}
$.ajax({
type:"GET",
url:"zap.json",
success:friends,
error:checkerror
});
function friends(data) {
console.log(data);
$.ajax({
type: "GET",
url: "test.json",
success: test,
error: checkerror
});
}
function test(data) {
console.log(data);
$.ajax({
type: "GET",
url: "test2.json",
success: function (data) {
console.log(data);
},
error: checkerror
})
}
};
Here errors are handled as different function and every callback function is declared outside which keeps the code tidy and readable. Output remains the same 😌
Promises
Promise is an object which shows a particular task has been completed or not(i.e. state of a particular task).
A promise may be in one of 3 possible states:
- Fulfilled: the operation completed successfully.
- Rejected: the operation failed.
- Pending: initial state, neither fulfilled nor rejected.
Promise users can attach callbacks to handle the fulfilled value or the reason for rejection.
Promise is better than simple call back as we can directly use return statement and pass new promise directly, it makes code more readable and understandable and easy to execute.
Let us consider an example to understand better that how it is better than normal callbacks.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Promises</title>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
window.onload = function(){
$.get("zap.json").then(function (value) {
console.log(value);
return $.get("test.json");
}).then(function (value) {
console.log(value);
return $.get("test2.json")
}).then(function (value) {
console.log(value);
})
}
</script>
</head>
<body>
</body>
</html>
output remains the same
function in .then
is called when the data is retrieved and we can return
new promise, hence it makes our code readable and output remains the same.
Generators
Generators provide a powerful alternative: they allow you to define an iterative algorithm by writing a single function which can maintain its own state.
generators are special type of functions which is used to perform
async tasks. It is defined as function*(){..}
on calling similarly
as functions it returns an iterator. In JavaScript an iterator is
an object that provides a next() method which returns the next item
in the sequence.
Let us consider an example :
window.onload = function () {
generator(function*(){
var zap = yield $.get("zap.json");
console.log(zap);
});
console.log("done");
function generator(temp) {
var gen = temp();
function checkandprint(output){
if(!output.done) {
output.value.then(function (data) {
return checkandprint(gen.next(data));
});
}
}
return checkandprint(gen.next());
}
};
here next()
returns the value of done
as true or false and iterator is
terminated when done
is false.
The next()
method also accepts a value which can be used to modify the
internal state of the generator. A value passed to next()
will be
treated as the result of the last yield
expression that paused the
generator.This pause help us make user-defined iterables.
There is no opposition between these two techniques. They exist together complementing each other nicely. Promises resolves the callback hell problem but even in promises there are callbacks and if the code is huge it becomes difficult to debug an issue. So we want to write asynchronous code in synchronous manner, Here comes the generators which gives us power to write asynchronous code which seems to be synchronous using promises, this combined concept is called Async/Await
What is the best way among all?
Callbacks is the fastest solution possible at this time (performance of native promises are not soo good). Promises with generators give you opportunity to write asynchronous code in synchronous fashion. But for now they are much slower than simple callbacks.