javascript - await - Promise.all: orden de valores resueltos
promise.all foreach (3)
Como ya se indicó en las respuestas anteriores,
Promise.all
agrega todos los valores resueltos con una matriz correspondiente al orden de entrada de las Promesas originales (consulte
Agregación de promesas
).
Sin embargo, me gustaría señalar que el pedido solo se conserva en el lado del cliente.
Para el desarrollador, parece que las promesas se cumplieron en orden, pero en realidad, las promesas se procesan a diferentes velocidades. Es importante saber cuándo trabaja con un servidor remoto porque el servidor podría recibir sus promesas en un orden diferente.
Aquí hay un ejemplo que demuestra el problema mediante el uso de tiempos de espera:
Promesa.todos
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)
En el código que se muestra arriba, se otorgan tres Promesas (A, B, C) a
Promise.all
.
Las tres promesas se ejecutan a diferentes velocidades (C es la más rápida y B la más lenta).
Es por eso que las declaraciones
console.log
de las Promesas aparecen en este orden:
C (fast)
A (slow)
B (slower)
Si las Promesas son llamadas AJAX, un servidor remoto recibirá estos valores en este orden.
Pero en el lado del cliente,
Promise.all
garantiza que los resultados se ordenan de acuerdo con las posiciones originales de la matriz
myPromises
.
Por eso el resultado final es:
[''A (slow)'', ''B (slower)'', ''C (fast)'']
Si desea garantizar también la ejecución real de sus Promesas, necesitaría un concepto como una cola Promesa. Aquí hay un ejemplo usando p-queue (tenga cuidado, necesita ajustar todas las promesas en las funciones):
Cola de promesa secuencial
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);
Resultado
A (slow)
B (slower)
C (fast)
[''A (slow)'', ''B (slower)'', ''C (fast)'']
Al mirar
MDN
, parece que los
values
pasados a la devolución de llamada
then()
de Promise.all contienen los valores en el orden de las promesas.
Por ejemplo:
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?
});
¿Alguien puede citar una especificación que indique en qué orden deben estar los
values
?
PD: Ejecutar un código como ese mostró que esto parece ser cierto, aunque eso no es una prueba, podría haber sido una coincidencia.
En breve, se conserva el orden .
Siguiendo la especificación a la que se vinculó,
Promise.all(iterable)
toma un
iterable
(es decir, un objeto que admite la interfaz
Iterator
) como parámetro y luego llama a
PerformPromiseAll( iterator, constructor, resultCapability)
con él, donde el último bucle sobre
iterable
usando
IteratorStep(iterator)
.
Esto significa que si el iterable que pasa a
Promise.all()
está estrictamente ordenado, aún se ordenarán una vez que se lo pase.
La resolución se implementa a través de
Promise.all() Resolve
donde cada promesa resuelta tiene una ranura interna
[[Index]]
, que marca el índice de la promesa en la entrada original.
Todo esto significa que la salida está estrictamente ordenada como entrada, siempre que la entrada esté estrictamente ordenada (por ejemplo, una matriz).
Puede ver esto en acción en el siguiente violín (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));
});
Sí, los valores en los
results
están en el mismo orden que las
promises
.
Se podría citar la
especificación ES6 en
Promise.all
, aunque es un poco complicado debido a la API de iterador utilizada y al constructor de promesa genérico.
Sin embargo, notará que cada devolución de llamada de resolución tiene un atributo
[[index]]
que se crea en la iteración de matriz de promesa y se utiliza para establecer los valores en la matriz de resultados.