返回文章列表
javascript

JavaScript Promises - Complete Guide

Understanding JavaScript Promises, async operations, and Promise methods like all, race, any for handling asynchronous programming

Aaron

Promise is a feature introduced in ES6 that provides built-in methods including all, race, resolve, reject, and others to handle asynchronous operations.

Promise Constructor

The Promise object constructor syntax is as follows:

let promise = new Promise(function(resolve, reject) {
  // executor function
});
  • resolve(value): Called when the operation completes successfully with a result value
  • reject(error): Called when an error occurs, with error as the error object

When new Promise is declared, the executor function runs automatically. If execution is successful, resolve is called; if an error occurs, reject is called.

Promise States and Results

The promise object returned by the new Promise constructor has the following internal properties:

  1. state — Initially “pending”, then changes to “fulfilled” when resolve is called, or “rejected” when reject is called
  2. result — Initially undefined, then becomes the value when resolve(value) is called, or the error when reject(error) is called

Important: The executor can only call one resolve or one reject:

let promise = new Promise(function(resolve, reject) {
  resolve("done");
  
  reject(new Error("...")); // ignored - first call wins
});

Handling Promise Results

.then()

The .then() method accepts two function parameters:

  • First parameter: Function executed when promise resolves
  • Second parameter: Function executed when promise rejects
promise.then(
  function(result) { /* handle successful result */ },
  function(error) { /* handle error */ }
);

.catch()

For error handling specifically:

promise.catch((error) => {
  // handle error
});

Promise Static Methods

Promise.all()

let promise = Promise.all(iterable);

Executes multiple promises and waits for ALL promises to complete. If any promise rejects, the result is that rejection error.

Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
    new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
    new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then((values) => console.log(values));
// Output: [1, 2, 3] (after 3 seconds)

Promise.all([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
    new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
    new Promise((resolve, reject) => setTimeout(() => reject(new Error('error')), 1000))  // 3
]).catch((error) => console.log(error));
// Output: Error: error (after 1 second)

Promise.race()

Waits only for the FIRST settled promise and returns its result:

Promise.race([
    new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
    new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
    new Promise(resolve => setTimeout(() => resolve(3), 1000))  // 3
]).then((value) => console.log(value));
// Output: 3 (after 1 second - fastest wins)

Promise.any()

Waits for the FIRST fulfilled promise and returns it. If all promises are rejected, returns a promise with AggregateError:

Promise.any([
  new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 1000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(1), 2000)),
  new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000))
]).then((value) => console.log(value));
// Output: 1 (first successful resolution)

Promise Method Comparison

MethodBehaviorResult
Promise.all()Waits for ALL to resolveArray of all results OR first rejection
Promise.race()Waits for FIRST to settleFirst settled result (resolve OR reject)
Promise.any()Waits for FIRST to resolveFirst resolved result OR AggregateError

Common Use Cases

Sequential vs Parallel Execution

// Sequential (slower)
async function sequential() {
  const result1 = await promise1(); // Wait for first
  const result2 = await promise2(); // Then wait for second
  return [result1, result2];
}

// Parallel (faster)
async function parallel() {
  const [result1, result2] = await Promise.all([
    promise1(), // Start both simultaneously
    promise2()
  ]);
  return [result1, result2];
}

Error Handling Best Practices

async function handleErrors() {
  try {
    const results = await Promise.all([
      fetchUserData(),
      fetchUserPosts(),
      fetchUserFriends()
    ]);
    return results;
  } catch (error) {
    console.error('One or more operations failed:', error);
    throw error;
  }
}

Key Takeaways

  1. Promise.all(): Use when you need ALL operations to succeed
  2. Promise.race(): Use for timeout scenarios or when you want the fastest response
  3. Promise.any(): Use when you need at least ONE operation to succeed
  4. Always handle errors: Use .catch() or try-catch with async/await
  5. Parallel > Sequential: Use Promise.all() for independent operations

Understanding Promises is essential for modern JavaScript development and forms the foundation for async/await syntax.