0% found this document useful (0 votes)
3 views

Asynchronous JavaScript

The document provides an overview of asynchronous programming in JavaScript, focusing on callbacks, promises, and event handling. It explains how to use setTimeout, setInterval, and XMLHttpRequest for asynchronous operations, as well as how to handle errors and chain promises effectively. Additionally, it covers the differences between client-side and Node.js asynchronous programming, emphasizing the importance of callbacks and event listeners.

Uploaded by

kilaruharika2003
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Asynchronous JavaScript

The document provides an overview of asynchronous programming in JavaScript, focusing on callbacks, promises, and event handling. It explains how to use setTimeout, setInterval, and XMLHttpRequest for asynchronous operations, as well as how to handle errors and chain promises effectively. Additionally, it covers the differences between client-side and Node.js asynchronous programming, emphasizing the importance of callbacks and event listeners.

Uploaded by

kilaruharika2003
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Asynchronous JavaScript

Asynchronous Programming with Callbacks:-


asynchronous programming in JavaScript is done withcallbacks. A callback is a function that you
write and then pass to some other function. That other function then invokes (“calls back”) your
function when some condition is met or some (asynchronous) event occurs. The invocation of
the callbackfunction you provide notifies you of the condition or event, and sometimes, the
invocation will include function arguments that provide additional details.
a) Timers:-One of the simplest kinds of asynchrony is when you want to run some code after a
certain amount of time has elapsed.
setTimeout(checkForUpdates, 60000);
The first argument to setTimeout() is a function and the second is a time intervalmeasured in
milliseconds. In the preceding code, a hypothetical checkForUpdates()function will be called
60,000 milliseconds (1 minute) after the setTimeout() call.
Example-1: Print “Hello world” after 3 seconds
<script>
function greet() {
document.write(“Hello world”)
}
setTimeout(greet, 3000)
document.write(“Print first”)
</script>
output:-
Print first
Hello world
setInterval:- Itallows us to run a function repeatedly, starting after the interval of time, then
repeating continuously at that interval.To stop further calls, we should call clearInterval(timerId).
The setInterval() function returns a timer object ID. You can pass this ID to
clearInterval(intervalId) at any time before the delayMilliSeconds expires to cancelthe timeout
function. For example:
myInterval = setInterval(myFunc, 10000);

clearInterval(myInterval);
Exampole:-
let i = 1;
const iMax = 3;
function sayHello() {
console.log('Hello number ' + i);
i = i + 1;
if (i>iMax) {
clearInterval(intervalID); // Canceling the repeating action of the `setInterval()` method
}
}
const intervalID = setInterval(sayHello, 1000);
output:
Hello number 1
Hello number 2
Hello number 3
b) Events:-
Client-side JavaScript programs are almost universally event driven. They typically wait for
the user to dosomething and then respond to the user’s actions. The web browser generates
anevent when the user presses a key on the keyboard, moves the mouse, clicks a
mousebutton, or touches a touchscreen device. Event-driven JavaScript programs
registercallback functions for specified types of events in specified contexts, and the
webbrowser invokes those functions whenever the specified events occur. These
callbackfunctions are called event handlers or event listeners, and they are registered
withaddEventListener().
The addEventListener() method is used to attach an event handler to a HTML document.
Syntax:
element.addEventListener(event, listener);
Event Handling using query selector
Using querySelector is a popular way of adding event listeners.
Example:-
functionlogHello(){
console.log('hello world');
}
// create event handler
document.querySelector('#form').addEventListener('click',logHello);
c) Network Events:-
function getCurrentVersionNumber(versionCallback)
{
let request = new XMLHttpRequest();
request.open("GET", "http://www.example.com/api/version");
request.send();
// Register a callback that will be invoked when the response arrives
request.onload = function() {
if (request.status === 200) {
// If HTTP status is good, get version number and call callback.
letcurrentVersion = parseFloat(request.responseText);
versionCallback(null, currentVersion);
} else {
// Otherwise report an error to the callback
versionCallback(response.statusText, null);
}
};
// Register another callback that will be invoked for network errors
request.onerror = request.ontimeout = function(e) {
versionCallback(e.type, null);
};
}
Client-side JavaScript code can use the XMLHttpRequest class plus callback functionsto
make HTTP requests and asynchronously handle the server’s response when it arrives.
The getCurrentVersionNumber() function defined heremakes an HTTP request and
defines event handlers that will be invokedwhen the server’s response is received or
when a timeout or other error causes therequest to fail.
getCurrentVersionNumber() function makes an asynchronous request, it cannot
synchronouslyreturn the value (the current version number) that the caller is interested in.
Instead,the caller passes a callback function, which is invoked when the result is ready
orwhen an error occurs. In this case, the caller supplies a callback function that
expectstwo arguments. If the XMLHttpRequest works correctly, then
getCurrentVersionNumber() invokes the callback with a null first argument and the
version number as thesecond argument. Or, if an error occurs, then
getCurrentVersionNumber() invokesthe callback with error details in the first argument
and null as the second argument.
d) Callbacks and Events in Node:-
The Node.js server-side JavaScript environment is deeply asynchronous and defines
many APIs that use callbacks and events. The default API for reading the contents of
a file, for example, is asynchronous and invokes a callback function when the contents of
the file have been read:
const fs = require("fs");
let options = {
};
fs.readFile("config.json", "utf-8", (err, text) => {
if (err) {
console.warn("Could not read config file:", err);
} else {
// Otherwise, parse the file contents and assign to the options object
Object.assign(options, JSON.parse(text));
}
// In either case, we can now start running the program
startProgram(options);
});
Node’s fs.readFile() function takes a two-parameter callback as its last argument. It
reads the specified file asynchronously and then invokes the callback. If the file was
read successfully, it passes the file contents as the second callback argument. If there
was an error, it passes the error as the first callback argument.
Notice that Node uses an on()method to register event listeners instead of
addEventListener():
Example:-
const https = require("https");
// Read the text content of the URL and asynchronously pass it to the callback.
functiongetText(url, callback) {
// Start an HTTP GET request for the URL
request = https.get(url);
// Register a function to handle the "response" event.
request.on("response", response => {
// The response event means that response headers have been received
lethttpStatus = response.statusCode;
response.setEncoding("utf-8"); // We're expecting Unicode text
let body = ""; // which we will accumulate here.
// This event handler is called when a chunk of the body is ready
response.on("data", chunk => { body += chunk; });
// This event handler is called when the response is complete
response.on("end", () => {
if (httpStatus === 200) { // If the HTTP response was good
callback(null, body); // Pass response body to the callback
} else { // Otherwise pass an error
callback(httpStatus, null); } });
});
request.on("error", (err) => {
callback(err, null);
});}
Promises
A promise in JavaScript is like a container for a future value. A promise lets you keep
working with your code while waiting for something else to finish, like loading data from a
server. When the data is ready, the promise will deliver it.
A promise can be in one of three states:
Pending: The promise is waiting for something to finish. For example, waiting for data to
load from a website.
Fulfilled: The promise has been completed successfully. The data you were waiting for is
now available.
Rejected: The promise has failed. Maybe there was a problem, like the server not
responding.
When you create a promise, you write some code that will eventually tell the promise
whether it was successful (fulfilled) or not (rejected).
The promise constructor takes only one argument which is a callback function
The callback function takes two arguments, resolve and reject.
o Perform operations inside the callback function and if everything went well then
call resolve.
o If desired operations do not go well then call reject.
Syntax
let promise = new Promise(function(resolve, reject){
//do something
});
Example:-
letmyPromise = new Promise(function(resolve, reject) {
let success = true; // change this to false to check error
if (success) {
resolve("The data has loaded successfully!");
} else {
reject("There was an error loading the data.");
}
});
a) Using a Promise
Once you have a promise, you can use it to do something when it’s fulfilled or rejected. You can
do this using two methods: then and catch.
Example:-
myPromise.then(function(message) {
// This runs if the promise is fulfilled
console.log(message);
}).catch(function(error) {
// This runs if the promise is rejected
console.log(error);
});
The then method is called when the promise is fulfilled. It takes a function as an argument,
which will run when the promise is successful.
The catch method is called when the promise is rejected. It also takes a function, which will run
if there’s an error.
Example:-
let promise = new Promise(function (resolve, reject) {
const x = "hello";
const y = "hello"
if (x === y) {
resolve();
} else {
reject();
}
});
promise.
then(function () {
console.log('Success, You are a GEEK');
}).
catch(function () {
console.log('Some error has occurred');
});
Output
Success, You are a GEEK
getJSON() starts an asynchronous HTTP request for the URL you specify and then,while that
request is pending, it returns a Promise object. The Promise object definesa then() instance
method. Instead of passing our callback function directly togetJSON(), we instead pass it to the
then() method. When the HTTP responsearrives, the body of that response is parsed as JSON,
and the resulting parsed value ispassed to the function that we passed to then().
getJSON(url).then(jsonData => {
// This is a callback function that will be asynchronously
// invoked with the parsed JSON value when it becomes available.
});
A Promise represents a single computation, andeach function registered with then() will be
invoked only once.
functiondisplayUserProfile(profile) { }
getJSON("/api/user/profile").then(displayUserProfile);
b) Handling errors with Promises
Asynchronous operations, particularly those that involve networking, can typicallyfail in a
number of ways and robust code has to be written to handle the errors.
For Promises, we can do this by passing a second function to the then() method:
getJSON("/api/user/profile").then(displayUserProfile, handleProfileError);
When something goes wrong in a synchronous computation, it throws an exceptionthat
propagates up the call stack until there is a catch clause to handle it. When anasynchronous
computation runs, its caller is no longer on the stack, so if somethinggoes wrong, it is simply not
possible to throw an exception back to the caller.
Instead, Promise-based asynchronous computations pass the exception to the second function
passed to then().So, in the code above, if getJSON() runs normally, it passes itsresult to
displayUserProfile(). If there is an error, then getJSON() passes an Error object to
handleProfileError().
The more idiomatic way to handle errors is:
getJSON("/api/user/profile").then(displayUserProfile).catch(handleProfileError);
A normal result from getJSON() is still passed to displayUserProfile(), but any error in
getJSON() or in displayUserProfile()get passed to handleProfileError().

c) Chaining Promises:-
One of the most important benefits of Promises is that they provide a natural way toexpress a
sequence of asynchronous operations as a linear chain of then() methodinvocations, without
having to nest each operation within the callback of the previousone.
Promise Chaining is a simple concept by which we may initialize another promise
inside our .then() method and accordingly we may execute our results. The function inside then
captures the value returned by the previous promise.The catch() method is used with the callback
when the promise is rejected or if an error occurs.
Example:-
<script>
letcountValue = new Promise(function (resolve, reject) {
resolve("Promise resolved");
});
// executes when promise is resolved successfully
countValue
.then(function successValue(result) {
console.log(result);
})
.then(function successValue1() {
console.log("You can call multiple functions this way.");
});
</script>
Output:-
Promise resolved
You can call multiple functions this way.
Example:-
letcountValue = new Promise(function (resolve, reject) {
reject('Promise rejected');
});
// executes when promise is resolved successfully
countValue.then(
functionsuccessValue(result) {
console.log(result);
}, )
// executes if there is an error
.catch(
functionerrorValue(result) {
console.log(result);
});
Output:-
Promise rejected

Method Chain:-When more than one method is invoked in a single expression like this,
fetch().then().then()
we call it a method chain. We know that the fetch() function returns a Promise object, and
wecan see that the first .then() in this chain invokes a method on that returnedPromise object. But
there is a second .then() in the chain, which means that the firstinvocation of the then() method
must itself return a Promise.
d) Resolving Promises:-
In order for Promise chains to work usefully, the output of task 2 must become the input to task
3. And in the example we’re considering here, the input to task 3 is the body of the URL that was
fetched, parsed as a JSON object. But, the return value of callback c1 is not a JSON object, but
Promise p4 for that JSON object. This seems like a contradiction, but it is not: when p1 is
fulfilled, c1 is invoked, and task 2 begins. And when p2 is fulfilled, c2 is invoked, and task 3
begins.
But just because task 2 begins when c1 is invoked, it does not mean that task 2 must end when c1
returns. Promises are about managing asynchronous tasks, after all, and if task 2 is asynchronous
(which it is, in this case), then that task will not be complete by the time the callback returns.
Example:-
function c1(response)
{ // callback 1
let p4 = response.json();
return p4; // returns promise 4
}
function c2(profile)
{ // callback 2
displayUserProfile(profile);
}
let p1 = fetch("/api/user/profile"); // promise 1, task 1
let p2 = p1.then(c1); // promise 2, task 2
let p3 = p2.then(c2); // promise 3, task 3

e) Promises and errors:-


The catch and finally methods
The .catch() method of a Promise is simply a shorthand way to call .then() with null as the first
argument and an error-handling callback as the second argument. Given any Promise p and a
callback c, the following two lines are equivalent:
p.then(null, c);
p.catch(c);
Example:-
fetch("/api/user/profile") // Start the HTTP request
.then(response => { // Call this when status and headers are ready
if (!response.ok) { // If we got a 404 Not Found or similar error
return null; // Maybe user is logged out; return null profile
}
// Now check the headers to ensure that the server sent us JSON.
// If not, our server is broken, and this is a serious error!
let type = response.headers.get("content-type");
if (type !== "application/json") {
throw new TypeError(`Expected JSON, got ${type}`);
}
// If we get here, then we got a 2xx status and a JSON content-type
// so we can confidently return a Promise for the response
// body as a JSON object.
return response.json();
})
.then(profile => { // Called with the parsed response body or null
if (profile) {
displayUserProfile(profile);
}
else { // If we got a 404 error above and returned null we end up here
displayLoggedOutProfilePage();
}
})
.catch(e => {
if (e instanceof NetworkError) {
// fetch() can fail this way if the internet connection is down
displayErrorMessage("Check your internet connection.");
}
else if (e instanceof TypeError) {
// This happens if we throw TypeError above
displayErrorMessage("Something is wrong with our server!");
}
else {
// This must be some kind of unanticipated error
console.error(e);
}
});

p1 is the Promise returned by the fetch() call. p2 is the Promise returned by the first .then() call,
and c1 is the callback that we pass to that .then() call. p3 is the Promise returned by the
second .then() call, and c2 is the callback we pass to that call. Finally, c3 is the callback that we
pass to the .catch() call.
f) Promises in Parallel:-
Promise.all() takes an array of Promise objects as its input and returns a Promise. The returned
Promise will be rejected if any of the input Promises are rejected. Otherwise, it will be fulfilled
with an array of the fulfillment values of each of the input Promises.
Both Promise.all() and Promise.allSettled() methods are the methods of a Promise object (which
is further a JavaScript object used to handle all the asynchronous operations) that are used to
handle multiple promises results simultaneously.

Promise.all() method:- It returns a single Promise after receiving one or more promises as input.
when all of the Promises in the input are satisfied, the returning promise is fulfilled. when any of
the inputs, or promises are refused, it rejects a promise with this first rejection reason.
Syntax:
Promise.all([promise_1 , promise_2, ...]).then(
// do something...
)
Promise.allSettled() method:- It returns a single Promise from one or more promises that are
passed in as input when all of the input’s promises have been settled, this promise is fulfilled and
an array of objects containing a description of each promise’s result is returned.
Syntax:
Promise.allSettled([promise_1 , promise_2, ...]).then(
// do something...
)
Example:- Promise.all()
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000) );
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500));
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800));
const promisesArray = [promise1, promise2, promise3];
Promise.all(promisesArray)
.then((results) => {
console.log("All promises resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error); });
Output:-
All promises resolved: [ 'Promise 1 resolved', 'Promise 2 resolved', 'Promise 3 resolved' ]

Example:- promise2 resolves after 500 seconds but promise3 rejects after 800 seconds so it
will not wait for promise1 and will return a response:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000));
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500));
const promise3 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 3 rejected"), 800));
const promisesArray = [promise1, promise2, promise3];
Promise.all(promisesArray)
.then((results) => {
document.write ("All promises resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
Output:-
At least one promise rejected: Promise 3 rejected
Example:- Promise.allSettled()
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000));
const promise2 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 2 resolved"), 500));
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800));
const promisesArray = [promise1, promise2, promise3];
Promise.allSettled(promisesArray).then((results) => {
console.log("All promises settled:", results); });
Output:-
[
{ status: 'fulfilled', value: 'Promise 1 resolved' },
{ status: 'rejected', reason: 'Promise 2 resolved' },
{ status: 'fulfilled', value: 'Promise 3 resolved' }
]
Promise.race():- race returns first promise with shortest delay whether it is resolved or rejected.
For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (resolved)
Promise 4 ==> 4 seconds (resolved)
Promise 5 ==> 5 seconds (resolved)
So, it will return us Promise 1 because it was the first one being returned.
Example:-
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000));
const promise2 = new Promise((_,reject) =>
setTimeout(() => reject("Promise 2 rejected"), 500));
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800));
const promisesArray = [promise1, promise2, promise3];
Promise.race(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
Output:-
At least one promise rejected: Promise 2 rejected
g) Making Promises
Promises based on synchronous values:-
Promise.resolve() takes a value as its single argument and returns a Promise that will
immediately (but asynchronously) be fulfilled to that value. Similarly, Promise.reject() takes a
single argument and returns a Promise that will be rejected with that value as the reason.
When we call Promise.resolve(), we typically pass the fulfillment value to create a
Promise object that will very soon fulfill to that value. If you pass a Promise p1 to
Promise.resolve(), it will return a new Promise p2, which is immediately resolved, but which will
not be fulfilled or rejected until p1 is fulfilled or rejected.
It is possible, but unusual, to write a Promise-based function where the value is computed
synchronously and returned asynchronously with Promise.resolve(). If you detect error
conditions (such as bad argument values) before beginning an asynchronous operation, you can
report that error by returning a Promise created with Promise.reject().Finally, Promise.resolve()
is sometimes useful to create the initial Promise in a chain of Promises.
you invoke the Promise() constructor and pass a function as its only argument. The
function you pass should be written to expect two parameters, which, by convention, should
be named resolve and reject. The constructor synchronously calls your function with function
arguments for the resolve and reject parameters. After calling your function, the Promise()
constructor returns the newly created Promise. That returned Promise is under the control of the
function you passed to the constructor. That function should perform some asynchronous
operation and then call the resolve function to resolve or fulfill the returned Promise or call the
reject function to reject the returned Promise. Your function does not have to be asynchronous: it
can call resolve or reject synchronously, but the Promise will still be resolved, fulfilled, or
rejected asynchronously if you do this.
Example:-
function wait(duration) {
// Create and return a new Promise
return new Promise((resolve, reject) => {
// If the argument is invalid, reject the Promise
if (duration < 0) {
reject(new Error("Time travel not yet implemented"));
}
// Otherwise, wait asynchronously and then resolve the Promise.
// setTimeout will invoke resolve() with no arguments, which means
// that the Promise will fulfill with the undefined value.
setTimeout(resolve, duration);
});
}
h) Promises in Sequence:-
Promise.all() makes it easy to run an arbitrary number of Promises in parallel. And Promise
chains make it easy to express a sequence of a fixed number of Promises. Running an arbitrary
number of Promises in sequence is trickier.
Example:-
function fetchSequentially(urls) {
// We'll store the URL bodies here as we fetch them
const bodies = [];
// Here's a Promise-returning function that fetches one body
function fetchOne(url) {
return fetch(url)
.then(response => response.text())
.then(body => {
// We save the body to the array, and we're purposely
// omitting a return value here (returning undefined)
bodies.push(body);
});
}
// Start with a Promise that will fulfill right away (with value undefined)
let p = Promise.resolve(undefined);
// Now loop through the desired URLs, building a Promise chain
// of arbitrary length, fetching one URL at each stage of the chain
for(url of urls) {
p = p.then(() => fetchOne(url));
}
// When the last Promise in that chain is fulfilled, then the
// bodies array is ready. So let's return a Promise for that bodies array
return p.then(() => bodies);
}
Async and wait:-
a) Await expressions:-
The await keyword takes a Promise and turns it back into a return value or a thrown exception.
Given a Promise object p, the expression await p waits until p settles. If p fulfills, then the value
of await p is the fulfillment value of p. On the other hand, if p is rejected, then the await p
expression throws the rejection value of p. We don’t usually use await with a variable that holds
a Promise; instead, we use it before the invocation of a function that returns a Promise:
let response = await fetch("/api/user/profile");
let profile = await response.json();
Any code that uses await is itself asynchronous.
b) async functions:- you can only use the await keyword within functions that have been
declared with the async keyword.
async function getHighScore() {
let response = await fetch("/api/user/profile");
let profile = await response.json();
return profile.highScore;
}
Declaring a function async means that the return value of the function will be a Promise even if
no Promise-related code appears in the body of the function. If an async function appears to
return normally, then the Promise object that is the real return value of the function will resolve
to that apparent return value. And if an async function appears to throw an exception, then the
Promise object that it returns will be rejected with that exception.
The getHighScore() function is declared async, so it returns a Promise. And because it returns a
Promise, we can use the await keyword with it:
displayHighScore(await getHighScore());
You can use the async keyword with any kind of function. It works with the function keyword as
a statement or as an expression. It works with arrow functions and with the method shortcut form
in classes and object literals.
c) Awaiting Multiple Promises:-
Suppose that we’ve written our getJSON() function using async:
async function getJSON(url) {
let response = await fetch(url);
let body = await response.json();
return body;
}
And now suppose that we want to fetch two JSON values with this function:
let value1 = await getJSON(url1);
let value2 = await getJSON(url2);
The problem with this code is that the fetch of the second URL will not begin until the first fetch
is complete. If the second URL does not depend on the value obtained from the first URL, then
we should probably try to fetch the two values at the same time.
In order to await a set of concurrently executing async functions, we use Promise.all() just as we
would if working with Promises directly:
let [value1, value2] = await Promise.all([getJSON(url1), getJSON(url2)]);
d) Implementation Details
Suppose you write an async function like this:
async function f(x) { /* body */ }
You can think about this as a Promise-returning function wrapped around the body of your
original function:
function f(x) {
return new Promise(function(resolve, reject) {
try {
resolve((function(x) { /* body */ })(x));
}
catch(e) {
reject(e);
}
}); }

You might also like