260

查看MDN,看起来values传递给then()Promise.all 的回调包含按承诺顺序排列的值。例如:

var somePromises = [1, 2, 3, 4, 5].map(Promise.resolve);
return Promise.all(somePromises).then(function(results) {
  console.log(results) //  is [1, 2, 3, 4, 5] the guaranteed result?
});

任何人都可以引用规范说明values应该按哪个顺序排列吗?

PS:运行这样的代码表明这似乎是真的,尽管这当然不能证明——这可能是巧合。

4

3 回答 3

357

很快,订单就被保留了

按照您链接到的规范,Promise.all(iterable)将 aniterable作为参数并在内部调用PerformPromiseAll(iterator, constructor, resultCapability)它,后者在iterableusing上循环IteratorStep(iterator)

解析是通过Promise.all() Resolve每个已解决的 promise 都有一个内部[[Index]]slot 来实现的,该 slot 标记了原始输入中 promise 的索引。


所有这意味着输出是严格排序的,因为您传递给 Promise.all() 的迭代是严格排序的(例如,一个数组)。

您可以在下面的小提琴(ES6)中看到这一点:

// Used to display results
const write = msg => {
  document.body.appendChild(document.createElement('div')).innerHTML = msg;
};

// Different speed async operations
const slow = new Promise(resolve => {
  setTimeout(resolve, 200, 'slow');
});
const instant = 'instant';
const quick = new Promise(resolve => {
  setTimeout(resolve, 50, 'quick');
});

// The order is preserved regardless of what resolved first
Promise.all([slow, instant, quick]).then(responses => {
  responses.map(response => write(response));
});

于 2015-01-21T12:06:54.960 回答
83

正如前面的答案已经说明的那样,Promise.all将所有已解析的值与与原始 Promises 的输入顺序相对应的数组聚合(请参阅Aggregating Promises)。

但是,我想指出,订单只保留在客户端!

对于开发人员来说,Promise 看起来是按顺序实现的,但实际上,Promise 的处理速度不同。了解何时使用远程后端很重要,因为后端可能会以不同的顺序接收您的 Promise。

这是一个使用超时来演示该问题的示例:

承诺.all

const myPromises = [
  new Promise((resolve) => setTimeout(() => {resolve('A (slow)'); console.log('A (slow)')}, 1000)),
  new Promise((resolve) => setTimeout(() => {resolve('B (slower)'); console.log('B (slower)')}, 2000)),
  new Promise((resolve) => setTimeout(() => {resolve('C (fast)'); console.log('C (fast)')}, 10))
];

Promise.all(myPromises).then(console.log)

In the code shown above, three Promises (A, B, C) are given to Promise.all. The three Promises execute at different speeds (C being the fastest and B being the slowest). That's why the console.log statements of the Promises show up in this order:

C (fast) 
A (slow)
B (slower)

If the Promises are AJAX calls, then a remote backend will receive these values in this order. But on the client side Promise.all ensures that the results are ordered according to the original positions of the myPromises array. That's why the final result is:

['A (slow)', 'B (slower)', 'C (fast)']

If you want to guarantee also the actual execution of your Promises, then you would need a concept like a Promise queue. Here is an example using p-queue (be careful, you need to wrap all Promises in functions):

Sequential Promise Queue

const PQueue = require('p-queue');
const queue = new PQueue({concurrency: 1});

// Thunked Promises:
const myPromises = [
  () => new Promise((resolve) => setTimeout(() => {
    resolve('A (slow)');
    console.log('A (slow)');
  }, 1000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('B (slower)');
    console.log('B (slower)');
  }, 2000)),
  () => new Promise((resolve) => setTimeout(() => {
    resolve('C (fast)');
    console.log('C (fast)');
  }, 10))
];

queue.addAll(myPromises).then(console.log);

Result

A (slow)
B (slower)
C (fast)

['A (slow)', 'B (slower)', 'C (fast)']
于 2018-02-15T17:57:13.657 回答
32

是的,中的值resultspromises.

有人可能会引用ES6 规范Promise.all,尽管由于使用了迭代器 api 和通用 Promise 构造函数,这有点令人费解。但是,您会注意到每个解析器回调都有一个[[index]]属性,该属性是在 promise-array 迭代中创建的,用于设置结果数组的值。

于 2015-01-21T12:04:52.023 回答