查看MDN,它看起来像传递给Promise的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?
});

谁能引用一个规范说明值应该在哪个顺序?

PS:运行这样的代码表明这似乎是正确的,尽管这当然没有证据-这可能是巧合。


当前回答

正如前面的答案已经说过的,承诺。all用一个与原始promise的输入顺序相对应的数组聚合所有已解析的值(参见聚合promise)。

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

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

下面是一个通过使用超时来演示该问题的示例:

Promise.all

const myPromises = [ new Promise((resolve) => setTimeout(() => {resolve('A (slow)');console.log('A (slow)')}, 1000)), 新的承诺((resolve) => setTimeout(() => {resolve('B(更慢)');console.log('B(较慢)')},2000)), new Promise((resolve) => setTimeout(() => {resolve('C (fast)');console.log('C (fast)')}, 10)) ]; Promise.all (myPromises) (console.log)

在上面所示的代码中,三个promise (A, B, C)被给予Promise.all。三个承诺以不同的速度执行(C是最快的,B是最慢的)。这就是为什么promise的console.log语句以这样的顺序显示:

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

如果promise是AJAX调用,则远程后端将按此顺序接收这些值。但是在客户端承诺。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)']

其他回答

正如前面的答案已经说过的,承诺。all用一个与原始promise的输入顺序相对应的数组聚合所有已解析的值(参见聚合promise)。

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

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

下面是一个通过使用超时来演示该问题的示例:

Promise.all

const myPromises = [ new Promise((resolve) => setTimeout(() => {resolve('A (slow)');console.log('A (slow)')}, 1000)), 新的承诺((resolve) => setTimeout(() => {resolve('B(更慢)');console.log('B(较慢)')},2000)), new Promise((resolve) => setTimeout(() => {resolve('C (fast)');console.log('C (fast)')}, 10)) ]; Promise.all (myPromises) (console.log)

在上面所示的代码中,三个promise (A, B, C)被给予Promise.all。三个承诺以不同的速度执行(C是最快的,B是最慢的)。这就是为什么promise的console.log语句以这样的顺序显示:

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

如果promise是AJAX调用,则远程后端将按此顺序接收这些值。但是在客户端承诺。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)']

简单地说,顺序被保留了。

遵循你链接到的规范,Promise.all(iterable)接受一个可迭代对象作为参数,并在内部使用它调用PerformPromiseAll(迭代器,构造函数,resultCapability),后者使用IteratorStep(迭代器)在可迭代对象上循环。

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


所有这些都意味着输出是严格有序的,因为传递给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)); });

是的,结果中的值和承诺的顺序是一样的。

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