JavaScript Promises: Managing Asynchronous Operations

Promises are a way to represent values that might be available now, in the future, or never. They provide a clean and structured way to work with asynchronous code, avoiding the issues associated with callbacks in javascript.

Basic Syntax:

A Promise can be in one of three states:

  • Pending: The initial state; the promise is neither fulfilled nor rejected.
  • Fulfilled: The operation completed successfully, and the promise has a resulting value.
  • Rejected: The operation failed, and the promise has a reason for the failure.
const myPromise = new Promise((resolve, reject) => {
  // Asynchronous operation
  if (/* operation is successful */) {
    resolve(result); // Fulfill the promise with a value
  } else {
    reject(error); // Reject the promise with a reason (error)
  }
});

// Using the Promise
myPromise
  .then((result) => {
    console.log("Fulfilled:", result);
  })
  .catch((error) => {
    console.error("Rejected:", error);
  });

Chaining Promises:

Promises can be chained using the .then() method, allowing for sequential execution of asynchronous operations.

const firstAsyncOperation = () => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("First operation completed");
      resolve(1);
    }, 1000);
  });
};

const secondAsyncOperation = (value) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Second operation completed");
      resolve(value + 1);
    }, 1000);
  });
};

firstAsyncOperation()
  .then((result) => secondAsyncOperation(result))
  .then((finalResult) => {
    console.log("Final result:", finalResult);
  })
  .catch((error) => {
    console.error("Error:", error);
  });

Error Handling with Promises:

Promises use the .catch() method to handle errors, making it easy to separate error handling from the main flow.

const asyncOperationWithError = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const success = Math.random() > 0.5; // Simulating success or failure
      if (success) {
        resolve("Operation completed successfully");
      } else {
        reject(new Error("Operation failed"));
      }
    }, 1000);
  });
};

asyncOperationWithError()
  .then((result) => {
    console.log("Success:", result);
  })
  .catch((error) => {
    console.error("Error:", error.message);
  });

Promisifying Callbacks:

Promises can be used to convert callback-based APIs into a promise-based style, making code more readable and manageable.

const readFilePromise = (path) => {
  return new Promise((resolve, reject) => {
    readFile(path, 'utf8', (err, data) => {
      if (err) {
        reject(err);
      } else {
        resolve(data);
      }
    });
  });
};

readFilePromise('/path/to/file.txt')
  .then((content) => {
    console.log('File content:', content);
  })
  .catch((error) => {
    console.error('Error reading file:', error.message);
  });

Conclusion:

Promises provide a cleaner and more structured way to handle asynchronous operations compared to traditional callbacks. They simplify error handling, allow for sequential chaining of operations, and make it easier to reason about asynchronous code.

Leave a Reply

Your email address will not be published. Required fields are marked *


Categories


Tag Cloud

.net algorithms angular api Array arrays async asynchronous basic-concepts big o blazor c# classes code components containers control-structures csharp data structures data types dictionaries docker dom dotnet framework functions git guide Inheritance javascript json leetcode linq lists loops methods MVC npm object oriented programming oop operators sorted try catch typescript web framework