Necesito llamar recursivamente a una API para recorrer las entradas secundarias y devolver los resultados filtrados antes de continuar. Inicialmente estaba poniendo los resultados en una matriz y luego haciendo un .forEach , y si encontraba una coincidencia, necesitaba recurrir a hacerlo; sin embargo, eso no funcionó debido al problema descrito en la respuesta a esta pregunta . Entonces, traté de modificar la respuesta a esa pregunta, pero todavía no está esperando.
const getDatabases = async (blockId) => { let databases = []; let childDatabases = []; const children = await getChildren(blockId); Promise.all(children.results .filter( (child) => { return (['child_database', 'database'].includes(child.type) || child.has_children === true); }) .map( async (child) => { if (['child_database', 'database'].includes(child.type)) { return { id: child.id, title: child.child_database.title }; } else { console.log(`Waiting on getDatabases for ${child.id}`); // 1 childDatabases = await getDatabases(child.id); return false; } }) ) .then((childDbs) => { console.log(`Got childDbs`); // 3, 4 databases = [...databases, ...childDatabases].filter(dbId => dbId !== false); return databases; }) .catch((err) => console.log(err)); } app.get('/api', async (req, res) => { const dashboardPage = await getDashboardPage(); const databases = await getDatabases(dashboardPage); console.log('No longer awaiting getDatabases'); // 2 ... } Entonces, la pregunta es, ¿por qué 2 sucede antes que 3 y 4, en lugar de después de ellos? No debería const databases = await getDatabases(dashboardPage); antes de 2 estar esperando todas las llamadas recursivas que pasan por childDatabases = await getDatabases(child.id); después de 1?
La respuesta directa fue que necesitaba await la Promise.all . De lo contrario, Promise.all está colgando y esperando el async/await dentro de él, antes de llegar a .then , pero la función principal solo dispara esas promesas y no devuelve nada, porque nadie le dijo que esperara. Tan simplemente,
const getDatabases = async (blockId) => { let databases = []; let dbsOfChildren = []; const children = await getChildren(blockId); await Promise.all(children.results .filter( (child) => { Vale la pena señalar que, por razones similares, no se pueden encadenar más métodos de matriz después de uno async . De lo contrario, al siguiente método encadenado se le pasará inmediatamente una matriz... de promesas no resueltas. Entonces, no puedes, por ejemplo,
await Promise.all(myArray .filter( (e) => { // do stuff }) .map( async (e) => { // do some async stuff }) .filter( // filter ); // <-- this won't work ) En cambio, debe esperar a que se resuelvan las promesas y luego hacer sus manipulaciones adicionales, por lo que lo coloca en un .then :
await Promise.all(myArray .filter( (e) => { // do stuff }) .map( async (e) => { // do some async stuff }) ) .then((myPromisesAreResolvedArray) => { return myMyPromisesAreResolvedArray.filter( // filter ); }) O, tal vez mejor, como se indica en los comentarios, simplemente almacene los resultados de las promesas esperadas (su matriz modificada) en una const y continúe con su código ...
const myPromisesAreResolvedArray = await Promise.all(myArray .filter( (e) => { // do stuff }) .map( async (e) => { // do some async stuff }) ) return myPromisesAreResolvedArray.filter( ... );