阿里云主机折上折
  • 微信号
Current Site:Index > The Promise.all() method

The Promise.all() method

Author:Chuan Chen 阅读数:7325人阅读 分类: JavaScript

Basic Concept of Promise.all() Method

Promise.all() is a static method of the Promise object in ECMAScript 6. It takes an iterable collection of Promises (usually an array) and returns a new Promise instance. This new Promise is resolved only when all input Promises are successfully resolved. If any of the Promises is rejected, it will be immediately rejected.

const promise1 = Promise.resolve(3);
const promise2 = 42;
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then((values) => {
  console.log(values); // [3, 42, "foo"]
});

How Promise.all() Works

The working mechanism of Promise.all() can be broken down into the following key points:

  1. It accepts an iterable object (usually an array) as an argument.
  2. Each element in the array is wrapped with Promise.resolve() to ensure they are all Promises.
  3. Returns a new Promise instance.
  4. When all input Promises are successfully resolved, the new Promise returns all results in an array.
  5. If any Promise is rejected, the new Promise is immediately rejected with that rejection reason.
const promises = [
  fetch('/api/data1'),
  fetch('/api/data2'),
  fetch('/api/data3')
];

Promise.all(promises)
  .then(responses => Promise.all(responses.map(r => r.json())))
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Return Value Characteristics of Promise.all()

The Promise returned by Promise.all() has the following characteristics:

  • The order of resolved values matches the input Promise order, even if some Promises resolve faster.
  • If the input is an empty array, it immediately resolves with an empty array.
  • Non-Promise values are treated as resolved Promises.
// Empty array case
Promise.all([]).then(values => {
  console.log(values); // []
});

// Mixed Promises and non-Promise values
Promise.all([1, 2, Promise.resolve(3), Promise.resolve(4)])
  .then(values => console.log(values)); // [1, 2, 3, 4]

Error Handling Mechanism

Error handling is one of the important features of Promise.all():

  • It adopts a "fail-fast" mechanism, meaning the first rejected Promise causes the entire Promise.all() to be rejected.
  • Results of other Promises are ignored, even if they are resolved later.
  • Errors can be caught using .catch().
const p1 = new Promise((resolve) => setTimeout(resolve, 100, 'one'));
const p2 = new Promise((resolve, reject) => setTimeout(reject, 200, 'two'));
const p3 = new Promise((resolve) => setTimeout(resolve, 300, 'three'));

Promise.all([p1, p2, p3])
  .then(values => console.log(values))
  .catch(reason => console.log(reason)); // "two"

Practical Application Scenarios

Promise.all() has various practical scenarios in front-end development:

  1. Parallel multiple API requests.
  2. Loading multiple resources simultaneously.
  3. Batch processing data.
// Parallel requests to multiple API endpoints
const userId = 123;
const endpoints = [
  `/api/users/${userId}`,
  `/api/users/${userId}/posts`,
  `/api/users/${userId}/followers`
];

const requests = endpoints.map(url => fetch(url).then(r => r.json()));

Promise.all(requests)
  .then(([user, posts, followers]) => {
    console.log('User:', user);
    console.log('Posts:', posts);
    console.log('Followers:', followers);
  });

Difference from Promise.race()

Promise.all() is often compared with Promise.race(), with essential differences:

  • Promise.all() waits for all Promises to complete.
  • Promise.race() only waits for the first completed Promise (whether resolved or rejected).
const p1 = new Promise(resolve => setTimeout(resolve, 500, 'one'));
const p2 = new Promise(resolve => setTimeout(resolve, 100, 'two'));

Promise.all([p1, p2]).then(values => console.log(values)); // After 500ms: ["one", "two"]
Promise.race([p1, p2]).then(value => console.log(value)); // After 100ms: "two"

Advanced Usage Examples

Promise.all() can be combined with other Promise methods for more complex logic:

// Promise.all with timeout mechanism
function fetchWithTimeout(url, timeout = 5000) {
  return Promise.race([
    fetch(url),
    new Promise((_, reject) =>
      setTimeout(() => reject(new Error('Request timeout')), timeout)
    )
  ]);
}

const urls = ['/api/data1', '/api/data2', '/api/data3'];
const requests = urls.map(url => fetchWithTimeout(url));

Promise.all(requests)
  .then(responses => Promise.all(responses.map(r => r.json())))
  .then(data => console.log(data))
  .catch(error => console.error('Error:', error));

Performance Optimization Considerations

Performance issues to note when using Promise.all():

  1. Avoid initiating too many parallel requests at once.
  2. Consider processing large numbers of Promises in batches.
  3. Be mindful of memory usage.
// Processing large numbers of Promises in batches
async function processInBatches(items, batchSize, processItem) {
  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    await Promise.all(batch.map(processItem));
    console.log(`Processed batch ${i / batchSize + 1}`);
  }
}

const items = Array(1000).fill().map((_, i) => i);
processInBatches(items, 50, item => {
  return new Promise(resolve => {
    // Simulate asynchronous processing
    setTimeout(() => resolve(item * 2), Math.random() * 100);
  });
});

Browser Compatibility

Browser support for Promise.all():

  • Fully supported in modern browsers.
  • Not supported in IE11 and below.
  • Supported in Node.js 0.12 and above.

For unsupported environments, a polyfill can be used:

// Simple Promise.all polyfill
if (!Promise.all) {
  Promise.all = function(promises) {
    return new Promise(function(resolve, reject) {
      if (!Array.isArray(promises)) {
        return reject(new TypeError('Argument must be an array'));
      }
      
      var remaining = promises.length;
      if (remaining === 0) {
        return resolve([]);
      }
      
      function resolver(index) {
        return function(value) {
          resolveAll(index, value);
        };
      }
      
      function resolveAll(index, value) {
        results[index] = value;
        if (--remaining === 0) {
          resolve(results);
        }
      }
      
      var results = new Array(remaining);
      for (var i = 0; i < promises.length; i++) {
        Promise.resolve(promises[i]).then(resolver(i), reject);
      }
    });
  };
}

Comparison with Promise.allSettled()

ES2020 introduced Promise.allSettled(), which differs from Promise.all():

  • Promise.allSettled() waits for all Promises to complete (whether resolved or rejected).
  • Returns an array of results containing the status and value/reason of each Promise.
const promises = [
  Promise.resolve(1),
  Promise.reject('Error occurred'),
  Promise.resolve(3)
];

Promise.allSettled(promises).then(results => {
  results.forEach(result => console.log(result));
  /*
  Output:
  {status: "fulfilled", value: 1}
  {status: "rejected", reason: "Error occurred"}
  {status: "fulfilled", value: 3}
  */
});

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.