Asynchronous JavaScript
Asynchronous JavaScript
// Output:
// Task 1
// Task 2
// Task 3
```
Asynchronous Programming
Concurrent Execution: Tasks can be initiated without
waiting for other tasks to complete. Tasks can run
simultaneously, or "in parallel."
Non-Blocking: Tasks can start while others are still running,
which means the program doesn't get held up by slow tasks.
More Complex: Writing and debugging asynchronous code
can be more challenging due to the need to manage multiple
tasks running concurrently.
Example with Callbacks:
```javascript
[Link]("Task 1");
setTimeout(() => {
[Link]("Task 2 (Asynchronous)");
}, 2000);
[Link]("Task 3");
// Output:
// Task 1
// Task 3
// Task 2 (Asynchronous) - after a 2-second delay
```
[Link]((message) => {
[Link](message);
});
[Link]("Task 3");
// Output:
// Task 1
// Task 3
// Task 2 (Asynchronous) - after a 2-second delay
```
[Link]("Task 3");
}
asyncFunction();
// Output:
// Task 1
// (After a 2-second delay)
// Task 2 (Asynchronous)
// Task 3
```
The concept of callbacks and the challenge often referred to as
"callback hell."
Callbacks
Definition: A callback is a function passed as an argument to
another function and is executed after the main function has
completed its task.
Usage: Callbacks are commonly used in asynchronous
programming to handle tasks like reading files, making API
requests, or performing database operations.
```javascript
function greet(name, callback) {
[Link]("Hello " + name);
callback();
}
function sayGoodbye() {
[Link]("Goodbye!");
}
greet("Alice", sayGoodbye);
// Output:
// Hello Alice
// Goodbye!
```
Callback Hell
Definition: "Callback hell" (also known as "Pyramid of
Doom") refers to the situation where multiple nested callbacks
make the code hard to read and maintain.
Symptoms: As more callbacks are nested within each other,
the code becomes increasingly difficult to understand and
debug due to the deeply nested structure.
Example of Callback Hell:
```javascript
doTask1(function(result1) {
doTask2(result1, function(result2) {
doTask3(result2, function(result3) {
doTask4(result3, function(result4) {
doTask5(result4, function(result5) {
// Continue nesting more callbacks...
});
});
});
});
});
```
```javascript
doTask1()
.then(result1 => doTask2(result1))
.then(result2 => doTask3(result2))
.then(result3 => doTask4(result3))
.then(result4 => doTask5(result4))
.catch(error => [Link](error));
```
2. Async/Await: The `async` and `await` keywords simplify
asynchronous code, making it look more like synchronous
code.
```javascript
async function performTasks() {
try {
const result1 = await doTask1();
const result2 = await doTask2(result1);
const result3 = await doTask3(result2);
const result4 = await doTask4(result3);
const result5 = await doTask5(result4);
} catch (error) {
[Link](error);
}
}
performTasks();
```
Exercise 1. Write a Promise-based function that simulates
fetching user data from a server. Use .then() and .catch() to
handle successful and failed responses.
Here's a Promise-based function that simulates fetching user
data from a server. The function `fetchUserData` returns a
Promise that resolves with user data after a delay or rejects
with an error message if something goes wrong.
```javascript
function fetchUserData(userId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// Simulate fetching user data
const success = [Link]() > 0.2; // 80% chance
of success
if (success) {
resolve({
userId: userId,
name: "John Doe",
email: "[Link]@[Link]",
age: 30
});
} else {
reject("Failed to fetch user data.");
}
}, 2000); // Simulate a 2-second delay
});
}
fetchUserData(1)
.then(userData => {
[Link]("User data fetched successfully:", userData);
})
.catch(error => {
[Link]("Error:", error);
});
```
In this example:
- The `fetchUserData` function simulates an API call by
returning a Promise.
- Inside the Promise, we use `setTimeout` to simulate a delay.
- The success of the operation is determined by a random
number, with an 80% chance of success.
- If successful, the Promise resolves with user data.
- If it fails, the Promise rejects with an error message.
- We use `.then()` to handle the successful response and
`.catch()` to handle any errors.
Introduction to Fetch API
The Fetch API is a modern way to make HTTP requests in
JavaScript. It's a cleaner and more powerful alternative to the
older `XMLHttpRequest`. By default, the Fetch API returns a
Promise that resolves to the Response object representing the
request's response.
```javascript
async function fetchUserData(userId) {
try {
// Simulate a delay to fetch user data
await new Promise(resolve => setTimeout(resolve,
2000));
// Simulate a successful response 80% of the time
if ([Link]() > 0.2) {
const userData = {
userId: userId,
name: "John Doe",
email: "[Link]@[Link]",
age: 30
};
[Link]("User data fetched successfully:",
userData);
} else {
throw new Error("Failed to fetch user data.");
}
} catch (error) {
[Link]("Error:", error);
}
}
```javascript
async function fetchPublicAPIData() {
try {
const response = await
fetch('[Link]
In this example:
Exercise 1: The `fetchUserData` function simulates fetching
user data with a delay and a success probability. It uses
`async/await` for asynchronous operations and error handling.
Exercise 2: The `fetchPublicAPIData` function makes a GET
request to the JSONPlaceholder API to fetch user data. It
handles the response, checks for errors, parses the data as
JSON, and logs the results to the console.
```javascript
async function fetchData(url) {
try {
const response = await fetch(url);
if (![Link]) {
throw new Error("Network response was not ok");
}
const data = await [Link]();
[Link]("Data fetched successfully:", data);
} catch (error) {
[Link]("Error fetching data:", error);
}
}
fetchData('[Link]
```
In this example, the `fetchData` function makes an HTTP
request using the Fetch API and handles any errors that might
occur during the process.
Building a Simple Async App
Let's build a simple asynchronous app that fetches and
displays user data from a public API (JSONPlaceholder).
We'll use `async/await` for asynchronous operations and
handle errors effectively.
1. HTML Structure:
Create a basic HTML structure with a button to trigger the
data fetch and a div to display the results.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Async App</title>
</head>
<body>
<h1>Async User Data Fetch</h1>
<button id="fetchButton">Fetch User Data</button>
<div id="userData"></div>
<script src="[Link]"></script>
</body>
</html>
```
2. JavaScript Code:
Add the following JavaScript code in a file named
`[Link]` to handle the data fetch and display the results:
```javascript
[Link]('fetchButton').addEventListener('cl
ick', fetchUserData);
function displayUserData(userData) {
const userDataDiv =
[Link]('userData');
[Link] = `
<h2>${[Link]}</h2>
<p>Email: ${[Link]}</p>
<p>Username: ${[Link]}</p>
<p>Phone: ${[Link]}</p>
<p>Website: ${[Link]}</p>
`;
}
```
Explanation:
1. HTML Structure: The HTML file contains a button and a
div to display the fetched user data.
2. JavaScript Code:
- The `fetchUserData` function is triggered when the button
is clicked.
- The function uses `async/await` to fetch user data from
the JSONPlaceholder API.
- If the fetch is successful, the user data is displayed using
the `displayUserData` function.
- If an error occurs, an error message is displayed.
● Exercise: Build a simple "User Profile Fetcher" app:
o Create an HTML page with a button and a section to
display user data.
o Use Fetch with async/await to call a public API and
retrieve user data.
o Display the data dynamically on the page.
o Handle errors and show appropriate error messages
on the page.
Step 1: Create an HTML Page
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>User Profile Fetcher</title>
<style>
body {
font-family: Arial, sans-serif;
}
#userData {
margin-top: 20px;
}
.error {
color: red;
}
</style>
</head>
<body>
<h1>User Profile Fetcher</h1>
<button id="fetchButton">Fetch User Profile</button>
<div id="userData"></div>
<script src="[Link]"></script>
</body>
</html>
```
```javascript
[Link]('fetchButton').addEventListener('cl
ick', fetchUserData);
async function fetchUserData() {
const userDataDiv =
[Link]('userData');
[Link] = "Loading...";
try {
const response = await
fetch('[Link]
if (![Link]) {
throw new Error("Network response was not ok");
}
const userData = await [Link]();
displayUserData(userData);
} catch (error) {
[Link] = `<p class="error">Error
fetching user data: ${[Link]}</p>`;
}
}
function displayUserData(userData) {
const userDataDiv =
[Link]('userData');
[Link] = `
<h2>${[Link]}</h2>
<p>Email: ${[Link]}</p>
<p>Username: ${[Link]}</p>
<p>Phone: ${[Link]}</p>
<p>Website: ${[Link]}</p>
`;
}
```
Explanation:
1. HTML Page:
- The HTML page contains a button (`Fetch User Profile`)
and a div (`userData`) to display the fetched user data.
- Basic styling is added to improve the appearance.
2. JavaScript Code:
- An event listener is added to the button to trigger the
`fetchUserData` function when clicked.
- The `fetchUserData` function uses `async/await` to fetch
user data from the JSONPlaceholder API.
- If the fetch is successful, the `displayUserData` function is
called to display the fetched data.
- If an error occurs, an error message is displayed in the
`userData` div.
With this setup, clicking the "Fetch User Profile" button will
fetch user data from the public API and display it on the page.
Errors are handled gracefully, and appropriate error messages
are shown to the user.
In this example:
- A new WebSocket connection is created with `new
WebSocket('[Link]
- Event listeners are added to handle the opening of the
connection, receiving messages, closing the connection, and
errors.
- The client sends a message to the server using
`[Link]('Hello Server!')`.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>WebSocket Example</title>
<style>
#messages {
margin-top: 20px;
font-family: Arial, sans-serif;
}
</style>
</head>
<body>
<h1>WebSocket Example</h1>
<button id="connectButton">Connect to
WebSocket</button>
<div id="messages"></div>
<script src="[Link]"></script>
</body>
</html>
```
JavaScript Code
```javascript
[Link]('connectButton').addEventListener
('click', connectWebSocket);
function connectWebSocket() {
const socket = new WebSocket('[Link]
const messagesDiv =
[Link]('messages');
[Link] = "Connecting...";
Explanation:
1. HTML Structure: The HTML page contains a button
(`Connect to WebSocket`) and a div (`messages`) to display
messages received from the WebSocket server.
2. JavaScript Code:
- An event listener is added to the button to trigger the
`connectWebSocket` function when clicked.
- The `connectWebSocket` function creates a new
WebSocket connection to the public server
`[Link]
- Event listeners handle the WebSocket events: `open`,
`message`, `close`, and `error`.
- When the connection is opened, a message is sent to the
server, and a log message is displayed on the page.
- When a message is received from the server, it is logged
and displayed on the page.
- When the connection is closed or an error occurs,
appropriate messages are displayed.
```javascript
if ([Link] === 'default' ||
[Link] === 'undefined') {
[Link]().then(permission => {
if (permission === 'granted') {
[Link]('Notification permission granted.');
} else {
[Link]('Notification permission denied.');
}
});
}
```
```javascript
function sendNotification(title, options) {
if ([Link] === 'granted') {
new Notification(title, options);
} else {
[Link]('Notification permission not granted.');
}
}
// Example usage
sendNotification('Hello!', {
body: 'This is a real-time notification.',
icon: 'path/to/[Link]'
});
```
1. HTML Structure:
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Real-Time Notifications</title>
</head>
<body>
<h1>Real-Time Notifications with WebSockets</h1>
<button id="connectButton">Connect to
WebSocket</button>
<script src="[Link]"></script>
</body>
</html>
```
2. JavaScript Code:
```javascript
[Link]('connectButton').addEventListener
('click', connectWebSocket);
function connectWebSocket() {
const socket = new
WebSocket('[Link]
Explanation:
1. HTML Structure:
- The HTML page contains a button (`Connect to
WebSocket`) that will initiate the WebSocket connection.
2. JavaScript Code:
- The `requestNotificationPermission` function requests
permission from the user to send notifications.
- The `sendNotification` function sends a notification if
permission is granted.
- The `connectWebSocket` function establishes a WebSocket
connection to the server.
- Event listeners handle the WebSocket events (`open`,
`message`, `close`, `error`) and send appropriate notifications
based on the events.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Notification System</title>
<style>
body {
font-family: Arial, sans-serif;
}
#messages {
margin-top: 20px;
}
.error {
color: red;
}
</style>
</head>
<body>
<h1>WebSocket Notification System</h1>
<button id="connectButton">Connect to
WebSocket</button>
<div id="messages"></div>
<script src="[Link]"></script>
</body>
</html>
```
```javascript
[Link]('connectButton').addEventListener
('click', connectWebSocket);
function connectWebSocket() {
const socket = new WebSocket('[Link]
const messagesDiv =
[Link]('messages');
[Link] = "Connecting...";
sendNotification('New Message', {
body: `Message from server: ${[Link]}`,
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
sendNotification('WebSocket Disconnected', {
body: 'The WebSocket connection has been closed.',
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
sendNotification('WebSocket Error', {
body: 'An error occurred with the WebSocket
connection.',
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
}
```
Explanation:
1. HTML Page:
- The HTML page contains a button (`Connect to
WebSocket`) and a div (`messages`) to display messages from
the WebSocket server.
- Basic styling is added to improve the appearance.
2. JavaScript Code:
- The `requestNotificationPermission` function requests
notification permission from the user.
- The `sendNotification` function sends a notification if
permission is granted.
- The `connectWebSocket` function establishes a WebSocket
connection to the public server `[Link]
- Event listeners handle WebSocket events (`open`,
`message`, `close`, `error`) and display appropriate
notifications.
- Customize the notification with a title, message, and icon.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Real-Time Data and Notification App</title>
<style>
body {
font-family: Arial, sans-serif;
}
#messages {
margin-top: 20px;
}
.error {
color: red;
}
</style>
</head>
<body>
<h1>Real-Time Data and Notification App</h1>
<button id="connectButton">Connect to
WebSocket</button>
<div id="messages"></div>
<script src="[Link]"></script>
</body>
</html>
```
```javascript
[Link]('connectButton').addEventListener
('click', connectWebSocket);
function connectWebSocket() {
const socket = new WebSocket('[Link]
const messagesDiv =
[Link]('messages');
[Link] = "Connecting...";
sendNotification('New Message', {
body: `Message from server: ${[Link]}`,
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
sendNotification('WebSocket Disconnected', {
body: 'The WebSocket connection has been closed.',
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
sendNotification('WebSocket Error', {
body: 'An error occurred with the WebSocket
connection.',
icon: 'path/to/[Link]' // Replace with the path to your
icon
});
});
}
```
Explanation:
1. HTML Structure: The HTML page contains a button
(`Connect to WebSocket`) and a div (`messages`) to display
messages from the WebSocket server. Basic styling is added
to improve the appearance.
2. JavaScript Code:
- Notification Permission: The
`requestNotificationPermission` function requests permission
from the user to send notifications.
- Sending Notifications: The `sendNotification` function
sends a notification if permission is granted.
- WebSocket Connection: The `connectWebSocket` function
establishes a WebSocket connection to the public server
`[Link]
- Event Listeners: Event listeners handle WebSocket events
(`open`, `message`, `close`, `error`) and display appropriate
notifications.
● Exercise: Build a “Real-Time Stock Ticker” or “Live
Weather Update” app:
o Use WebSockets to receive data in real time.
o Display the data on the web page and send a
notification when a specific event occurs.
Let's build a "Live Weather Update" app that uses WebSockets
to receive data in real time, displays the data on a web page,
and sends a notification when a specific event occurs. For this
example, we'll use a public WebSocket server for live weather
updates.
Step 1: Create the HTML Structure
Create a basic HTML page with a section to display the
weather updates and a button to connect to the WebSocket
server.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>Live Weather Update App</title>
<style>
body {
font-family: Arial, sans-serif;
}
#weatherUpdates {
margin-top: 20px;
}
.error {
color: red;
}
</style>
</head>
<body>
<h1>Live Weather Update App</h1>
<button id="connectButton">Connect to
WebSocket</button>
<div id="weatherUpdates"></div>
<script src="[Link]"></script>
</body>
</html>
```
Step 2: Add JavaScript to Handle WebSocket Connection,
Display Weather Updates, and Send Notifications
function connectWebSocket() {
// Replace with a public WebSocket server for live weather
updates
const socket = new WebSocket('[Link]
websocket-server');
const weatherUpdatesDiv =
[Link]('weatherUpdates');
[Link] = "Connecting...";
function displayWeatherUpdate(weatherData) {
const weatherUpdatesDiv =
[Link]('weatherUpdates');
[Link] += `
<h2>${[Link]}</h2>
<p>Temperature: ${[Link]}°C</p>
<p>Condition: ${[Link]}</p>
<p>Humidity: ${[Link]}%</p>
<p>Wind Speed: ${[Link]} km/h</p>
`;
}
```
Explanation:
1. HTML Structure: The HTML page contains a button
(`Connect to WebSocket`) and a div (`weatherUpdates`) to
display weather updates from the WebSocket server. Basic
styling is added to improve the appearance.
2. JavaScript Code:
- Notification Permission: The
`requestNotificationPermission` function requests permission
from the user to send notifications.
- Sending Notifications: The `sendNotification` function
sends a notification if permission is granted.
- WebSocket Connection: The `connectWebSocket` function
establishes a WebSocket connection to the weather server.
- Event Listeners: Event listeners handle WebSocket events
(`open`, `message`, `close`, `error`) and display appropriate
notifications.
- Display Weather Updates: The `displayWeatherUpdate`
function updates the HTML with the received weather data
and sends a notification if the weather condition is "Rain".