Tengo dificultades para entender por qué todavía tengo promesas pendientes después de esperar Promise.all() .
En el siguiente ejemplo, estoy creando una matriz de promesas llamando a una función asíncrona en cada elemento de una matriz, usando .map() .
Ahora, ¿por qué la promesa todavía se muestra como pendiente? La forma en que (mal) lo entiendo ahora mismo:
then() se activa una vez que se resuelve la promesa de storeData()storeData() se resuelve una vez que se devuelve newDataArraynewDataArray se devuelve una vez que se resuelven todas las promesas dentro de promisesArray o una vez que se rechaza la primera. storeData(OldDataArray).then(values => console.log(values)) // console shows: // { id: 1, data: Promise { <pending> } }, // { id: 2, data: Promise { <pending> } } const storeData = async (OldDataArray) => { try { const promisesArray = OldDataArray.map((item) => { let newData = downloadMoreDetails(item.id, item.group); //async function, see below return { id: item.id, data: newData, }; }); const newDataArray = await Promise.all(promisesArray); // <-- I'm awaiting all promises to complete before assigning to newDataArray return newDataArray; } catch (error) { console.log(error) } }; const downloadMoreDetails = async (id, group) => { const response = await fetch( `example.com/id/group.xml` ); if (!response.ok) { throw new Error(`HTTP error ${response.status}`); } const str = await response.text(); const json = convert.xml2json(str, { compact: true, spaces: 2, }); return json; };newData es una promesa, pero no estás esperando la promesa. En cambio, está esperando una serie de objetos {id: item.id, data: newData } que tiene la promesa dentro. Promise.all() no mira dentro de esos objetos para encontrar la promesa y esperar esa promesa. Solo ve una serie de objetos simples, lo que significa que no tiene nada que hacer. Puedes arreglar eso haciendo esto:
const storeData = async (OldDataArray) => { try { const promisesArray = OldDataArray.map(async (item) => { let newData = await downloadMoreDetails(item.id, item.group); //async function, see below return { id: item.id, data: newData, }; }); return Promise.all(promisesArray); } catch (error) { // log and rethrow error so the caller gets the rejection console.log(error); throw error; } }; Esto cambia la devolución de llamada .map() para que sea async . Eso hace dos cosas beneficiosas. Primero, significa que la matriz resultante de .map() será una matriz de promesas, ya que la devolución de llamada async siempre devuelve una promesa. Y, en segundo lugar, le permite usar await dentro de la devolución de llamada para que pueda completar su objeto devuelto con los datos reales, no con una promesa.
Luego, la return desde el interior de la devolución de llamada async hará que ese valor se convierta en el valor resuelto de la promesa de que la función async está devolviendo.
Tenga en cuenta que también podría haberlo hecho sin agregar async/await de esta manera:
const storeData = (OldDataArray) => { const promisesArray = OldDataArray.map((item) => { return downloadMoreDetails(item.id, item.group).then(newData => { return { id: item.id, data: newData, }; }); }); return Promise.all(promisesArray).catch(error => { // log and rethrow error so the caller gets the rejection console.log(error); throw error; }); }; En esta versión, devuelve directamente una promesa de la devolución de llamada .map() y se asegura de que la promesa se resuelva en su objeto de datos.