Transitioning from Callbacks to Promises for Asynchronous JavaScript

Strategies for replacing callback-based asynchronous code with Promises to improve readability and maintainability in JavaScript.

0 likes
10 views

Rule Content

---
description: Enforce the use of Promises over callbacks for asynchronous operations in JavaScript to enhance code readability and maintainability.
globs: ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
tags: [JavaScript, Promises, Asynchronous]
priority: 2
version: 1.0.0
---

# Transitioning from Callbacks to Promises for Asynchronous JavaScript

## Context

- **When to Apply**: In all JavaScript codebases where asynchronous operations are performed.
- **Prerequisites**: Familiarity with JavaScript's asynchronous programming patterns, including callbacks and Promises.

## Requirements

- **Use Promises Instead of Callbacks**: Replace traditional callback-based asynchronous code with Promises to improve readability and maintainability.
- **Error Handling**: Implement `.catch()` for error handling in Promises to ensure errors are properly managed.
- **Chaining**: Utilize `.then()` chaining for sequential asynchronous operations to avoid callback nesting (callback hell).
- **Async/Await Syntax**: Prefer `async/await` syntax over `.then()` chaining for cleaner and more readable asynchronous code.

## Examples

<example>
**Good Example**: Using Promises with `fetch` API

fetch('https://api.example.com/data')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    console.log(data);
  })
  .catch(error => {
    console.error('There was a problem with the fetch operation:', error);
  });
In this example, Promises are used to handle asynchronous operations, providing clear error handling and avoiding nested callbacks.
</example>

<example>
**Good Example**: Using `async/await` with `fetch` API

async function fetchData() {
  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error('There was a problem with the fetch operation:', error);
  }
}

fetchData();
This example demonstrates the use of `async/await` syntax, making the asynchronous code more readable and maintainable.
</example>

<example type="invalid">
**Bad Example**: Using Callbacks with `XMLHttpRequest`

function fetchData(callback) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', 'https://api.example.com/data', true);
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        callback(null, JSON.parse(xhr.responseText));
      } else {
        callback(new Error('Request failed'));
      }
    }
  };
  xhr.send();
}

fetchData(function (error, data) {
  if (error) {
    console.error('There was a problem with the request:', error);
  } else {
    console.log(data);
  }
});
This example uses callbacks for handling asynchronous operations, which can lead to callback nesting and reduced readability.
</example>