Promise.all:已解决的值的顺序

时间:2015-01-21 11:44:06

标签: javascript promise es6-promise

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

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:运行这样的代码表明这似乎是真的,虽然这当然没有证据 - 这可能是巧合。

3 个答案:

答案 0 :(得分:198)

很快,保留订单

根据您链接的规范,Promise.all(iterable)iterable(即支持Iterator接口的对象)作为参数,稍后调用PerformPromiseAll( iterator, constructor, resultCapability)使用它,后者使用IteratorStep(iterator)循环iterable 这意味着如果您传递给Promise.all()的可迭代内容是严格排序的,那么一旦传入它们仍然会被订购。

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


所有这些意味着输出严格按输入进行排序,只要输入是严格排序的(例如,数组)。

你可以在下面的小提琴(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));
});

答案 1 :(得分:26)

是的,results中的值与promises的顺序相同。

有人可能会引用ES6 spec on Promise.all,但由于使用了迭代器api和泛型promise构造函数,它有点复杂。但是,您会注意到每个解析器回调都有一个[[index]]属性,该属性是在promise-array迭代中创建的,用于设置结果数组上的值。

答案 2 :(得分:23)

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

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

对于开发者来说,看起来Promise是按顺序完成的,但实际上,Promises以不同的速度处理。了解何时使用远程后端非常重要,因为后端可能会以不同的顺序接收您的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)

在上面显示的代码中,三个Promises(A,B,C)被赋予Promise.all。三个Promise以不同的速度执行(C是最快的,B是最慢的)。这就是Promise的console.log语句按此顺序出现的原因:

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

如果Promises是AJAX调用,则远程后端将按此顺序接收这些值。但是在客户端Promise.all确保根据myPromises数组的原始位置对结果进行排序。这就是最终结果的原因:

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

如果您还想保证Promise的实际执行,那么您需要一个像Promise队列这样的概念。以下是使用p-queue的示例(请注意,您需要将所有Promise包装在函数中):

顺序承诺队列

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);

<强>结果

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

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