Asynchronous programming is an essential technique in JavaScript that allows your code to run in the background without blocking the execution of other code. This is in contrast to synchronous JavaScript, where tasks are executed one at a time. For example, when you click a button on a web page, you don't want the entire page to reload. Instead, you want the button to be disabled and a loading indicator to be displayed. Once the task is complete, the page can be updated and the button can be re-enabled.
There are two main ways to write asynchronous JavaScript code: Callbacks and Promises.
Callbacks
JavaScript functions are executed in the sequence they are called. Not in the sequence they are defined.
function myFirst(){
console.log("I am first");
}
function mySecond(){
console.log("I am second");
}
mySecond();
myFirst();
The above example finally gives the output -
I am second
I am first
Sometimes you would like to have better control over when to execute a function.
Suppose you want to do a calculation, and then display the result.
You could call a calculator function (myCalculator
), save the result, and then call another function (myDisplayer
) to display the result:
function myDisplayer(some) {
console.log(some);
}
function myCalculator(num1, num2) {
let sum = num1 + num2;
return sum;
}
let result = myCalculator(5, 5);
myDisplayer(result);
Output:
10
Or, you could call a calculator function (myCalculator
), and let the calculator function call the display function (myDisplayer
):
function myDisplayer(some) {
console.log(some);
}
function myCalculator(num1, num2) {
let sum = num1 + num2;
myDisplayer(sum);
}
myCalculator(5, 5);
Output:
10
The problem with the second example above, is that you have to call two functions to display the result.
The problem with the third example, is that you cannot prevent the calculator function from displaying the result.
Now it is time to bring callback.
Callbacks are functions that are passed to another function as an argument. The callback function is called when the other function is finished executing.
function myDisplayer(some) {
console.log(some);
}
function myCalculator(num1, num2, myCallback) {
let sum = num1 + num2;
myCallback(sum);
}
myCalculator(5, 5, myDisplayer);
In the example above, myDisplayer
is called a callback function because it is passed to myCalculator()
as an argument. Here, you can call the calculator function (myCalculator
) with a callback (myCallback
), and let the calculator function run the callback after the calculation is finished.
Output:
10
In the real world, callbacks are most often used with asynchronous functions.
A typical example is JavaScript setTimeout()
.
function myFunction() {
console.log("I am running...");
}
setTimeout(myFunction, 3000);
console.log("Hello JavaScript");
Hello JavaScript
I am running...
In the above example, myFunction
is used as a callback.
3000 is the number of milliseconds before time-out, so myFunction()
will be called after 3 seconds but the other code (console.log("Hello JavaScript");
)will be run without blocking its (setTimeout()
) execution.
With asynchronous programming, JavaScript programs can start
long-running tasks, and continue running other tasks in parallel.
But, asynchronus programmes are difficult to write and difficult to debug.
Because of this, most modern asynchronous JavaScript methods don't use
callbacks. Instead, in JavaScript, asynchronous programming is solved
using Promises instead.
Promises
Promises are a powerful tool for handling asynchronous operations in JavaScript. They can help to make your code more readable and easier to maintain. If the promise is successful, it will produce a resolved value, but if something goes wrong then it will produce a reason why the promise failed.
Syntax:
let myPromise = new Promise(function(myResolve, myReject) {
myResolve(); // when successful
myReject(); // when error
});
myPromise.then(
function(value) { /* code if successful */ },
function(error) { /* code if some error */ }
);
A JavaScript Promise object can be:
Pending - the result is undefined.
Fulfilled - the result is a value.
Rejected - the result is an error object.
Example 1:
function myDisplayer(some) {
console.log(some);
}
let myPromise = new Promise(function(myResolve, myReject) {
let x = 0;
if (x == 0) {
myResolve("OK");
} else {
myReject("Error");
}
});
myPromise.then(
function(value) {myDisplayer(value);},
function(error) {myDisplayer(error);}
);
Output:
OK
Example 2:
const myPromise = new Promise(function(myResolve, myReject) {
setTimeout(function(){
myResolve("I am running after 3 seconds...");
}, 3000);
});
myPromise.then(function(value) {
console.log(value);
});
I am running after 3 seconds...
JavaScript Async/Await
The keyword async
before a function makes the function return a promise:
Example 1:
async function myFunction() {
return "Hello";
}
Example 2:
function myDisplayer(some) {
console.log(some);
}
async function myFunction() {
return "Hello";
}
myFunction().then(
function(value) {myDisplayer(value);}
);
Output:
Hello
The await
keyword can only be used inside an async
function.
/* The await keyword makes the function pause the execution
and wait for a resolved promise before it continues */
async function myDisplay() {
let myPromise1 = new Promise(function(resolve) {
setTimeout(() => {
resolve("I am first code");
}, 3000);
});
let myPromise2 = new Promise(function(resolve) {
resolve("I am second code");
});
let value1 = await myPromise1;
let value2 = await myPromise2;
console.log(value1);
console.log(value2);
}
myDisplay();
I am first code
I am second code
In the above example, myDisplay()
function pauses the execution for myPromise1
to be resolved. After myPromise1
, myPromise2
will be resolved.