Promise.all: порядок разрешенных значений

Рассматривая MDN, он выглядит как values, переданный обратному сообщению then() для Promise.all, содержит значения порядка promises. Например:

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: Выполнение такого кода показало, что это кажется правдой, хотя это, конечно, не доказательство - это могло быть совпадением.

Ответ 1

Вскоре порядок сохраняется.

Следуя спецификации, с которой вы связаны, Promise.all(iterable) принимает iterable (то есть объект, который поддерживает Iterator interface) как параметр, а затем - вызовы PerformPromiseAll (итератор, конструктор, resultCapability) с ним, где последний перебирает итеративный с помощью IteratorStep (iterator)код>.
Это означает, что если, если итерабельность, которую вы передаете в Promise.all(), строго упорядочена, они все равно будут упорядочены после прохождения.

Разрешение выполняется через Promise.all() Resolve, где каждое разрешенное обещание имеет внутренний слот [[Index]], который отмечает индекс обещания в исходном входе.


Все это означает, что вывод строго упорядочен как вход, если вход строго упорядочен (например, массив).

Вы можете увидеть это в действии в приведенном ниже скрипте (ES6):

 //Используется для отображения результатов
const write = msg = > {
 document.body.appendChild(document.createElement('div')). innerHTML = msg;
};

// Различные операции с асинхронной скоростью
const slow = new Promise (resolve = > {
 setTimeout (разрешение, 200, "медленный" );
});
const instant = 'instant';
const quick = new Promise (resolve = > {
 setTimeout (разрешить, 50, "быстро" );
});

// Порядок сохраняется независимо от того, что разрешено первым
Promise.all([медленный, мгновенный, быстрый]), затем (response = > {
 response.map(response = > write (response));
});Код>

Ответ 2

Да, значения в results находятся в том же порядке, что и promises.

Можно было бы указать спецификацию ES6 на Promise.all, хотя она немного запутана из-за использованного итератора api и универсального конструктора обещаний. Тем не менее, вы заметите, что каждый обратный вызов resolver имеет атрибут [[index]], который создается в итерации с обещанием и используется для установки значений в массиве результатов.

Ответ 3

Как уже отмечалось в предыдущих ответах, Promise.all объединяет все разрешенные значения с массивом, соответствующим порядку ввода исходных обещаний (см. Агрегирование обещаний).

Однако я хотел бы указать, что заказ сохраняется только на стороне клиента!

Разработчику кажется, что обещания были выполнены в порядке, но на самом деле обещания обрабатываются с разной скоростью. Это важно знать, когда вы работаете с удаленным бэкэнд, потому что бэкэнд может получать ваши обещания в другом порядке.

Вот пример, демонстрирующий проблему с помощью тайм-аутов:

Promise.all

  const myPromises = [
 new Promise ((разрешить) = > setTimeout (() = > {разрешить ( "A (медленный)" ); console.log( "A (медленный)" )}, 1000)),
 new (Promise) ((разрешить) = > setTimeout (() = > {разрешить ('B (медленнее)'); console.log('B (медленнее)')}, 2000)),
 new Promise ((разрешить) = > setTimeout (() = > {resolve ('C (fast)'); console.log('C (fast)')}, 10))
];

Promise.all(myPromises).then(console.log)код>