6. What is a promise in JavaScript and how does it work?
hard
A promise in JavaScript is an object that represents the eventual completion (or failure) of an asynchronous operation and its resulting value. It allows us to write cleaner and more readable code by providing a way to handle the success or failure of a promise and execute code accordingly.

A promise has three possible states: fulfilled, rejected, or pending. When an asynchronous operation is performed, it returns a promise that is initially in the pending state. Once the operation completes, the promise's state is updated to either fulfilled or rejected, depending on whether the operation was successful or not.

The promise object has several methods that can be used to handle its states and values. The most commonly used methods are:

1. `then()` - this method takes a callback function as an argument and executes it when the promise is fulfilled. If the promise is rejected, the callback function is not executed.
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Operation completed');
  }, 2000);
});

promise.then(result => {
  console.log(result); // logs 'Operation completed' after 2 seconds
});
In this example, we create a promise that resolves after 2 seconds with the value 'Operation completed'. We then use the `then()` method to execute a callback function that logs the resolved value to the console.
2. `catch()` - this method takes a callback function as an argument and executes it when the promise is rejected.
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('Operation failed');
  }, 2000);
});

promise.catch(error => {
  console.log(error); // logs 'Operation failed' after 2 seconds
});
In this example, we create a promise that rejects after 2 seconds with the value 'Operation failed'. We then use the `catch()` method to execute a callback function that logs the rejected value to the console.

3. `finally()` - this method takes a callback function as an argument and executes it regardless of whether the promise is fulfilled or rejected.
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Operation completed');
  }, 2000);
});

promise.finally(() => {
  console.log('Promise settled'); // logs 'Promise settled' after 2 seconds, regardless of fulfillment or rejection
});

In this example, we create a promise that resolves after 2 seconds with the value 'Operation completed'. We then use the `finally()` method to execute a callback function that logs a message to the console, regardless of whether the promise is fulfilled or rejected.

Overall, promises provide a powerful and flexible way to handle asynchronous operations in JavaScript. They allow us to write cleaner and more readable code by providing a way to handle the success or failure of a promise and execute code accordingly.