Estoy leyendo "JavaScript elocuente" y al final del capítulo Asíncrono hay una sección sobre la brecha de ejecución en operaciones asíncronas y muestra un ejemplo. El siguiente código de ejemplo del libro no se puede ejecutar, ya que utiliza un escenario inventado.
function anyStorage(nest, source, name) { if (source == nest.name) return storage(nest, name); else return routeRequest(nest, source, "storage", name); } async function chicks(nest, year) { let list = ""; await Promise.all(network(nest).map(async name => { list += `${name}: ${ await anyStorage(nest, name, `chicks in ${year}`) }\n`; })); return list; } Dice que el problema con este código, según tengo entendido, es que cada llamada asíncrona, por ejemplo, anyStorage en realidad concatenará una list vacía y no podrá ver la mutación de otras llamadas asíncronas.
Traté de replicar este problema de la siguiente manera:
function delay(n) { return Promise.resolve(setTimeout(()=>{}, n*1000)); } async function asyncSum(a) { let sum = 0; await Promise.all(a.map(async i => sum += await delay(i))); return sum; } asyncSum([1,2,3,4]).then(value => console.log(value));Pero esto funciona como se esperaba. Imprime la suma correctamente. Entonces, ¿entendí mal el libro o hay algo mal con mi ejemplo?
El problema en el código original es que aquí:
list += `${name}: ${ await ... La list += es como hacer list = list + - pero la segunda lista:
list = list + ^^^^ hace referencia a la list en ese momento , antes de que se haya completado cualquiera de las llamadas asincrónicas. Eventualmente, uno de ellos completará y asignará a la list . Pero una vez que se resuelva el siguiente, debido a que la list que tiene se refiere al original, no al recién actualizado, los resultados anteriores se perderán.
Aquí hay una demostración:
const getMultipliedNum = num => Promise.resolve(num * 3); (async() => { let list = ""; await Promise.all([1, 2, 3].map(async num => { list += `${num}: ${ await getMultipliedNum(num)}\n`; })); console.log(list); })(); Su ejemplo tiene el mismo problema, aunque la función de delay está rota: el resultado es 4, que es solo el resultado de la llamada final a setTimeout (porque setTimeout devuelve la ID de tiempo de espera). Arreglarlo para demostrar el problema:
function delay(n) { return Promise.resolve(n); } async function asyncSum(a) { let sum = 0; await Promise.all(a.map(async i => sum += await delay(i))); return sum; } asyncSum([1,2,3,4]).then(value => console.log(value)); El resultado es 4, en lugar de 10; esto demuestra que sum += await somethingElse dentro de un ciclo paralelo no funciona.
Otra forma de verlo:
sum += await somethingElsees como hacer
const currentValueOfSum = sum; sum = currentValueOfSum + await somethingElse;