Asynchronous Programming in JavaScript - Guide For Beginners
Asynchronous Programming in JavaScript - Guide For Beginners
In traditional (synchronous) programming, each person would have to wait for the person before
them to finish their task before starting their own.
But with asynchronous programming, everyone can start and work on their tasks simultaneously
without waiting for the others to finish.
For example, a program can send a request to a server while handling user input and processing
data, all at the same time. This way, the program can run more efficiently.
Forum Donate
In this article, we will delve into the world of asynchronous programming in JavaScript, exploring
the different techniques and concepts that are used to achieve this powerful programming
paradigm.
From callbacks to promises and async/aawait, you will understand how to harness the power of
asynchronous programming in your JavaScript projects.
Imagine you're cooking dinner and have a list of tasks, like boiling water for pasta, frying chicken,
and making a salad.
You would do these tasks one at a time and wait for each one to finish before moving to the next.
Synchronous programming works similarly, where the computer will complete one task before
moving on to the next. This makes it easy to understand and predict what the computer will do at
any given time.
Here's an example of synchronous code in JavaScript: Forum Donate
function secondTask() {
console.log("Task 2");
}
function thirdTask() {
console.log("Task 3");
}
This code will output the following messages in the order they appear:
"Task 1"
"Task 2"
"Task 3"
The code will execute the tasks in the order you see them and wait for each task to be completed
before moving on to the next one.
For example, let's say that a synchronous program performs a task that requires waiting for a
response from a remote server. The program will be stuck waiting for the response and cannot do
anything else until the response is returned. This is known as blocking, and it can lead to an
application appearing unresponsive or "frozen" to the user.
function someLongRunningFunction() {
let start = Date.now();
while (Date.now() - start < 5000) {
// do nothing
}
Forum Donate
return "Hello";
Learn to code — free 3,000-hour curriculum
}
console.log('Starting...');
console.log('...Finishing');
In this example:
Then it calls the someLongRunningFunction , which simulates a long-running task that takes 5
seconds to complete. This function will block the execution of the rest of the program while
it runs.
Once the function completes, it will return "Hello", and the program will log it on the console.
During the 5 seconds that someLongRunningFunction() is being executed, the program will be
blocked, become unresponsive, and be unable to execute the next line of code. This can cause the
program to take a long time to complete and make the application unresponsive to the user.
However, if the program is executed asynchronously, it will continue to run the next line of code
instructions rather than becoming blocked. This will enable the program to remain responsive and
execute other code instructions while waiting for the timeout to complete.
Asynchronous programming allows a program to continue working on other tasks while waiting for
external events, such as network requests, to occur. This approach can greatly improve the
performance and responsiveness of a program.
Forum
For example, while a program retrieves data from a remote server, it can continue to execute other Donate
tasks such as responding to user inputs.
Learn to code — free 3,000-hour curriculum
console.log("Start of script");
setTimeout(function() {
console.log("First timeout completed");
}, 2000);
console.log("End of script");
In this example, the setTimeout method executes a function after a specified time. The function
passed to setTimeout will be executed asynchronously, which means that the program will
continue to execute the next line of code without waiting for the timeout to complete.
Start of script
End of script
First timeout completed
As you can see, console.log("First timeout completed") will be executed after 2 seconds.
Meanwhile, the script continues to execute the next code statement and doesn't cause any
"blocking" or "freezing" behaviour.
Illustration of a clown
Forum Donate
In code, a callback function is a function that is passed as an argument to another function, and it is
executed after the first function has finished running. It's commonly used in JavaScript to handle
asynchronous operations like fetching data from a server, waiting for a user's input, or handling
events.
Here is a simple example of how you can use a callback function to handle an asynchronous
operation:
// Declare function
function fetchData(callback) {
setTimeout(() => {
const data = {name: "John", age: 30};
callback(data);
}, 3000);
}
In this example:
We have a function called fetchData that uses the setTimeout method to simulate an
asynchronous operation. The function takes a callback as an argument.
The callback function is then passed the data retrieved by the function after the timeout has
been completed.
The setTimeout method is used to execute the callback after a specified time (in this case, 3
seconds). The callback will be executed asynchronously, which means that the program will
continue to execute the next line of code without waiting for the timeout to complete.
As you can see, console.log("First timeout completed") will be executed after 3 seconds.
Meanwhile, the script continues to execute the next statement, console.log("Data is being
fetched..."); .
This is the core concept of asynchronous programming. The script doesn't wait for the Forum Donate
asynchronous operation to complete. It just continues to execute the next instruction.
Learn to code — free 3,000-hour curriculum
This happens when you chain multiple callbacks together, one after the other, creating a pyramid-
like structure of indentation called callback hell, also known as the "Pyramid of Doom".
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
getEvenEvenMoreData(c, function(d) {
getFinalData(d, function(finalData) {
console.log(finalData);
});
});
});
});
});
In this example:
1. The getData function takes a callback as an argument and is executed after data is
retrieved.
2. The callback function then takes the data and calls the getMoreData function, which also
takes a callback as an argument, and so on.
This nesting of callbacks can make the code difficult to maintain, and the indentation makes it even
harder to see the overall structure of the code.
To avoid callback hell, you can use a more modern way of handling async operations known as
promises. Promises provide a more elegant way of handling the asynchronous flow of a program
compared to callback functions. This is the focus of the next section.
How Do Promises Work? Forum Donate
A promise in JavaScript is a placeholder for a future value or action. By creating a promise, you are
essentially telling the JavaScript engine to "promise" to perform a specific action and notify you
once it is completed or fails.
Next, callback functions are then attached to the promise to handle the outcome of the action.
These callbacks will be invoked when the promise is fulfilled (action completed successfully) or
rejected (action failed).
As a JavaScript developer, you will likely spend more time consuming promises returned by
asynchronous Web APIs and managing their outcomes rather than creating them yourself.
The constructor takes a single argument: a function called executor . The "executor" function is
called immediately when the promise is created, and it takes two arguments: a resolve function
and a reject function.
Forum Donate
// Initialize a promise
const myPromise = new Promise(function(resolve, reject) => {})
console.log(myPromise);
As you can see, the promise has a pending status and an undefined value. This is because nothing has
been set up for the promise object yet, so it's going to sit there in a pending state forever without
any value or result.
Now, let's set up myPromise to resolve with a string printed to the console after 2 seconds.
It's important to note that a promise is said to be settled when it is resolved or rejected.
Now that you know how promises are created, let's look at how you may consume them.
1. Obtain a reference to the promise: To consume a promise, you first need to obtain a
reference to it. Based on the code from the previous section, our reference to a promise will
be the myPromise object.
2. Attach callbacks to the promise: Once you have a reference, you can attach callback
functions by using the .then and .catch methods. The .then method is called when a
promise is fulfilled and the .catch method is called when a promise is rejected.
3. Wait for the promise to be fulfilled or rejected: Once you've attached callbacks to the
promise, you can wait for the promise to be fulfilled or rejected.
Once the promise is fulfilled, the .then callback method will be called with the resolved value. And
if the promise is rejected, the .catch method will be called with an error message.
You can also add the .finally() method, which will be called after a promise is settled. This means
that .finally() will be invoked regardless of the status of a promise (whether resolved or
rejected).
myPromise
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
})
.finally(() => {
//code here will be executed regardless of the status
//of a promise (fulfilled or rejected)
});
The pattern involves connecting multiple promises in a sequence, where the output of one promise
is passed as input to the next promise.
The linking of the promises is achieved using the then() method. This method uses a callback
function as an argument and returns a new promise. The new promise is then resolved with the
value returned by the callback function.
fetch('https://example.com/data')
.then(response => response.json())
.then(data => processData(data))
.then(processedData => {
// do something with the processed data
})
.catch(error => console.log(error))
The .catch method at the end of the chain will handle any errors that occurred in any of the
previous promises.
It's important to keep in mind that .then methods are executed asynchronously and in order, each
one waiting for the previous one to be resolved, and that the returned value of each .then will be
passed as an argument to the next one.
Error Handling
When a promise is rejected, it will trigger the .catch() method, which handles errors. The
.catch() method takes a single argument, which is the error thrown.
Another way of handling errors in a promise is by using the "try-catch" block inside a .then
method.
Here is an example:
fetch("https://api.github.com/users/octocat")
.then((response) => response.json())
.then((data) => {
try {
//processing received data
console.log(data);
} catch (error) {
console.log(error);
}
})
.catch((error) => console.log(error));
The fetch() function makes a request to the GitHub API to fetch user data.
The "try-catch" block is used inside the second .then method to handle any error that may
occur when processing the data received from the server.
And the outer .catch method will only catch errors that occur during the fetch request.
Handling errors is very important because promises are used to handle asynchronous operations,
and these operations may fail for various reasons.
If an error occurs during the execution of a promise and it is not handled, the program will continue
to execute and may lead to unexpected behaviour or crashes.
By handling errors, we can ensure that the program can continue to function even when an error
occurs and also provide meaningful feedback to the user about the problem.
Forum
How to Use the Promise.all Method Donate
Learnan
The Promise.all() method takes to array
code —offree 3,000-hour
promises curriculum
as input and returns a single promise that is
fulfilled when all input promises have been fulfilled. It can be useful when you wait for multiple
promises to be resolved before taking action.
Here, promise1 , promise2 , and promise3 are promises that are fetching data from three different
URLs.
Now, you can use Promise.all([promise1, promise2, promise3]) to wait for all the promises to
resolve before doing something with the data, as shown below.
The then method is then called on the returned promise to log the resolved values of all the
input promises in the order they were passed to Promise.all() .
Note that in an instance where any input promises are rejected, the returned promise will also be
rejected with the value of the first rejected promise.
Here is an example of how to use the Fetch API to fetch data from a server:
fetch('https://some-api.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Error:', error);
});
In this example,
The fetch() method is used to make a request to the server located at "https://some-
api.com/data". The returned value is a promise that will be fulfilled with the server's
response.
The first .then() method is called to consume the promise and extract JSON data from the
response.
The next then() method is called to log the extracted data to the console.
If any errors occur, they will be caught in the catch() method and logged to the console.
I hope the above explanation helps to clear up any confusion about the Fetch API and allows you to
better understand the examples provided in this article.
await is a keyword that is used inside an async function to pause the execution of the
function until a promise is resolved.
getData();
In this example,
Forum Donate
the getData function is declared as an asynchronous function using the async keyword.
Learn to code — free 3,000-hour curriculum
Inside the asynchronous function, we use the await keyword to wait for the fetch
function to complete and retrieve some data from an API.
Once the data is retrieved, we use await again to wait and parse the retrieved data as
JSON.
"Aync/Await" is a powerful tool for handling asynchronous operations. It allows for more readable
and maintainable code by eliminating the need for callbacks and providing a more intuitive way to
handle asynchronous operations.
Using the "async" keyword before a function definition and the "await" keyword before an
asynchronous operation makes the code look more like synchronous code, making it easier to
understand.
Overall, "Async/Await" is valuable to the JavaScript developer's toolbox and can significantly
simplify handling asynchronous operations in your code.
Conclusion
In summary, asynchronous programming is an essential concept in JavaScript that allows your code
to run in the background without blocking the execution of other code.
Developers can create more efficient and responsive applications by using features like callbacks,
async/await, and promises.
Asynchronous programming can be tricky to understand at first. But with practice and a solid
understanding of the concepts, it becomes a powerful tool for building high-performance web
applications.
If you enjoyed this article and want to learn more about programming, follow me on Instagram at
@alege_dev, where I post regular updates and tips on various programming topics.
Dickson Boateng
Experienced Frontend Developer who crafts code and words to create delightful experiences. Transforming tech
jargons into accessible content.
If you read this far, tweet to the author to show them you care. Tweet a thanks
Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000
people get jobs as developers. Get started
Forum Donate
freeCodeCamp is a donor-supported tax-exempt 501(c)(3) charity organization (United States Federal Tax Identification Number: 82-
0779546)
Our mission: to help people learn to code for free. We accomplish this by creating thousands of videos, articles, and interactive coding lessons -
all freely available to the public. We also have thousands of freeCodeCamp study groups around the world.
Donations to freeCodeCamp go toward our education initiatives, and help pay for servers, services, and staff.
Trending Guides
Bash If Statement CS vs IT
Our Charity
About Alumni Network Open Source Shop Support Sponsors Academic Honesty Code of Conduct Privacy Policy