Asynchronous Programming in JavaScript

Jul 12, 2024

Asynchronous Programming in JavaScript 🕒

Overview

In this two-part tutorial, we learn the essentials of asynchronous programming in JavaScript covering callbacks, promises, async/await, and the Fetch API. Part 1 introduces concepts and techniques, while Part 2 applies these to build three projects.

Prerequisites

  • Basic understanding of HTML
  • Basic understanding of CSS
  • Basic understanding of JavaScript

Part 1: Conceptual Foundations

Synchronous vs Asynchronous Programming

  • Synchronous Programming: Executes tasks sequentially, e.g., Task 1, Task 2, Task 3.

    • Problematic for tasks needing a significant time, like fetching API data (Blocking).
  • Asynchronous Programming: Allows other processes to run while waiting for tasks to complete (Non-blocking).

    • Benefits: Improved application performance, efficient data collection, better user experience.

Callbacks

  • Functions passed as arguments to other functions and executed after an event occurs.
  • Example: Using setTimeout to understand asynchronous behavior but leading to callback hell due to nesting.

Callback Hell

  • Example: Nested callbacks for executing tasks sequentially, making code difficult to read and maintain.

Promises

  • Promises provide a way to handle async operations more efficiently than callbacks.
  • Three States of a Promise: Pending, Fulfilled, Rejected.
  • Creating a Promise:
let promise = new Promise((resolve, reject) => {
  let condition = true;
  if (condition) {
    resolve('Success');
  } else {
    reject('Error');
  }
});
  • Consuming Promises with then and catch:
promise.then(value => {
  console.log(value); // Success
}).catch(error => {
  console.error(error); // Error
});
  • Chaining Promises: Allows sequential execution of promises.

async/await

  • Syntactic sugar for working with promises, making async code look synchronous.
  • Allows using await keyword inside async functions.

Example: Chocolate Brownies

  • Creating functions returning promises and consuming them using async and await:
async function bakeBrownies() {
  await preheatOven();
  await mixIngredients();
  await bake();
}

Error Handling with try/catch

try {
  await someAsyncFunction();
} catch (error) {
  console.error('Error:', error);
}

Part 2: Building Projects

Project 1: Chuck Norris Jokes Fetcher

  • HTML Structure: Header, button, and image placeholder.
  • Fetch API & async/await: Fetch jokes from an API and display on the webpage.
async function loadJoke() {
  try {
    let response = await fetch('https://api.chucknorris.io/jokes/random');
    let data = await response.json();
    document.getElementById('joke-container').innerText = data.value;
  } catch (error) {
    console.error('Error:', error);
  }
}

Project 2: Weather App

  • HTML Structure: Input for city name, and various display elements for weather data.
  • Fetch API & async/await: Get weather data for a city and dynamically update the DOM.
async function getWeather(city) {
  try {
    const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=YOUR_API_KEY`);
    const data = await response.json();
    updateDOM(data);
  } catch (error) {
    console.error('Error:', error);
  }
}

Project 3: Pokémon API

  • HTML Structure: Input for Pokémon name and a section to display Pokémon image.
  • Fetch API & async/await: Fetch Pokémon data and display it dynamically.
async function getPokemon(name) {
  try {
    const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${name.toLowerCase()}`);
    const data = await response.json();
    document.getElementById('pokemon-image').src = data.sprites.front_default;
  } catch (error) {
    console.error('Error:', error);
  }
}

Final Notes

  • Asynchronous programming improves user experience by avoiding blocking tasks.
  • Utilize async/await for cleaner and more maintainable code.
  • Practical use of Fetch API explored through building real-world projects.