javascript - try - node js async
Matriz de JavaScript.reduce con async/await (3)
Parece tener algunos problemas que incorporan async / await con .reduce (), así:
const data = await bodies.reduce(async(accum, current, index) => {
const methodName = methods[index]
const method = this[methodName]
if (methodName == ''foo'') {
current.cover = await this.store(current.cover, id)
console.log(current)
return {
...accum,
...current
}
}
return {
...accum,
...method(current.data)
}
}, {})
console.log(data)
El objeto de data
se registra antes de que this.store
...
Sé que puede utilizar Promise.all
con bucles asíncronos, pero ¿se aplica eso a .reduce()
?
El problema es que sus valores acumuladores son promesas, son valores de retorno de async function
. Para obtener una evaluación secuencial (y todas, excepto la última iteración que debe esperarse), debe usar
const data = await array.reduce(async (accumP, current, index) => {
const accum = await accumP;
…
}, Promise.resolve(…));
Dicho esto, para async
/ await
, en general recomendaría usar loops planos en lugar de métodos de iteración de matrices , son más eficaces y, a menudo, más simples.
Me gusta la respuesta de Bergi, creo que es el camino correcto.
También me gustaría mencionar una biblioteca mía, llamada Awaity.js
Lo que le permite utilizar sin esfuerzo funciones como reduce
, map
y filter
con async / await
:
import reduce from ''awaity/reduce'';
const posts = await reduce([1,2,3], async (posts, id) => {
const res = await fetch(''/api/posts/'' + id);
const post = await res.json();
return {
...posts,
[id]: post
};
}, {})
posts // { 1: { ... }, 2: { ... }, 3: { ... } }
Puede envolver todo el mapa / reducir los bloques de iteradores en su propio Promise.resolve y esperar a que se complete. Sin embargo, el problema es que el acumulador no contiene los datos / objetos resultantes que esperaría en cada iteración. Debido a la cadena interna async / await / Promise, el acumulador será real. Promesas que probablemente aún no se hayan resuelto a pesar de usar una palabra clave await antes de su llamada a la tienda (lo que podría llevarlo a creer que la iteración no será realmente efectiva). volver hasta que la llamada se complete y el acumulador se actualice.
Si bien esta no es la solución más elegante, una opción que tiene es mover su variable de objeto de datos fuera del alcance y asignarla como un permiso para que se produzca la vinculación y la mutación adecuadas. Luego, actualice este objeto de datos desde el interior de su iterador a medida que se resuelven las llamadas asíncronas / esperar / prometer.
/* allow the result object to be initialized outside of scope
rather than trying to spread results into your accumulator on iterations,
else your results will not be maintained as expected within the
internal async/await/Promise chain.
*/
let data = {};
await Promise.resolve(bodies.reduce(async(accum, current, index) => {
const methodName = methods[index]
const method = this[methodName];
if (methodName == ''foo'') {
// note: this extra Promise.resolve may not be entirely necessary
const cover = await Promise.resolve(this.store(current.cover, id));
current.cover = cover;
console.log(current);
data = {
...data,
...current,
};
return data;
}
data = {
...data,
...method(current.data)
};
return data;
}, {});
console.log(data);