JavaScript Promise.reject() Method: Creating Rejected Promises

The Promise.reject() method in JavaScript is a static method of the Promise object that returns a new Promise object that is rejected with a given reason. This is particularly useful when you need to create a promise that immediately fails, typically for error handling or when a function determines that it cannot proceed.

Purpose of Promise.reject()

The primary purpose of Promise.reject() is to create a promise that is already in the rejected state. This is often used to propagate errors, handle exceptional cases, or signal that an asynchronous operation has failed.

Syntax

The syntax for Promise.reject() is straightforward:

Promise.reject(reason);

Here, reason is the value with which the promise is rejected. It can be an error object, a string, or any other value that describes why the promise was rejected.

Key Attributes

| Attribute | Type | Description |
| ——— | ——- | —————————————————————————— |
| reason | Any | The reason for the promise rejection. This value is passed to the .catch() handler. |
| Returns | Promise | A new Promise object that is already rejected with the given reason. |

Basic Examples

Example 1: Rejecting a Promise with a String

In this example, we create a rejected promise with a simple string as the reason.

const rejectedPromise1 = Promise.reject("Operation failed: Invalid input");

rejectedPromise1.catch((error) => {
  console.error("Rejected:", error);
});

Output:

Rejected: Operation failed: Invalid input

Example 2: Rejecting a Promise with an Error Object

It’s often best practice to reject promises with Error objects to provide more context about the failure.

const rejectedPromise2 = Promise.reject(new Error("Database connection error"));

rejectedPromise2.catch((error) => {
  console.error("Rejected:", error.message);
});

Output:

Rejected: Database connection error

Example 3: Rejecting a Promise with a Custom Error Object

You can also create custom error classes to provide even more specific error information.

class CustomError extends Error {
  constructor(message, code) {
    super(message);
    this.code = code;
    this.name = "CustomError";
  }
}

const rejectedPromise3 = Promise.reject(new CustomError("Authentication failed", 401));

rejectedPromise3.catch((error) => {
  console.error("Rejected:", error.name, "-", error.message, "(Code:", error.code, ")");
});

Output:

Rejected: CustomError - Authentication failed (Code: 401)

Practical Use Cases

Use Case 1: Handling Invalid Input

Suppose you have a function that validates user input. If the input is invalid, you can reject a promise to signal the failure.

function validateInput(input) {
  return new Promise((resolve, reject) => {
    if (typeof input === 'string' && input.length > 5) {
      resolve(input);
    } else {
      reject("Invalid input: Input must be a string with more than 5 characters.");
    }
  });
}

validateInput("short")
  .then((result) => console.log("Valid input:", result))
  .catch((error) => console.error("Error:", error));

validateInput("This is a valid input")
  .then((result) => console.log("Valid input:", result))
  .catch((error) => console.error("Error:", error));

Output:

Error: Invalid input: Input must be a string with more than 5 characters.
Valid input: This is a valid input

Use Case 2: Failing Asynchronous Operations

In scenarios where an asynchronous operation fails, Promise.reject() can be used to propagate the error.

function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = false;
      if (success) {
        resolve("Data fetched successfully");
      } else {
        reject(new Error("Failed to fetch data from the server."));
      }
    }, 1000);
  });
}

fetchData()
  .then((data) => console.log("Success:", data))
  .catch((error) => console.error("Error:", error.message));

Output:

Error: Failed to fetch data from the server.

Use Case 3: Combining with async/await

Promise.reject() works seamlessly with async/await for cleaner asynchronous code.

async function processData() {
  try {
    const data = await fetchData();
    console.log("Data:", data);
  } catch (error) {
    console.error("Error:", error.message);
  }
}

async function fetchData() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = false;
      if (success) {
        resolve("Data fetched successfully");
      } else {
        reject(new Error("Failed to fetch data."));
      }
    }, 1000);
  });
}

processData();

Output:

Error: Failed to fetch data.

Use Case 4: Rejecting After a Condition

function checkAge(age) {
    return new Promise((resolve, reject) => {
        if (age >= 18) {
            resolve("Access granted.");
        } else {
            reject("Access denied: You must be 18 or older.");
        }
    });
}

checkAge(16)
    .then(message => console.log("Success:", message))
    .catch(error => console.error("Error:", error));

checkAge(20)
    .then(message => console.log("Success:", message))
    .catch(error => console.error("Error:", error));

Output:

Error: Access denied: You must be 18 or older.
Success: Access granted.

Tips and Best Practices

  • Use Error objects: Always reject promises with Error objects or instances of custom error classes to provide meaningful error information.
  • Handle rejections: Ensure that you always handle rejected promises using .catch() or try/catch blocks to prevent unhandled promise rejections.
  • Propagate errors: Use Promise.reject() to propagate errors from one asynchronous operation to another.
  • Avoid unnecessary rejections: Only reject promises when a genuine error or exceptional condition occurs.

Conclusion

The Promise.reject() method is a fundamental tool for creating rejected promises in JavaScript. It is essential for error handling, signaling failures, and propagating errors in asynchronous operations. By using Promise.reject() effectively, you can write more robust and maintainable asynchronous code.