Necesito crear una función, que devolverá una Promesa y llamará a otra función que tendrá una llamada axios.get() . Axios.get() llama a una API que devuelve datos con la siguiente estructura:
{ count: 87, //total number of records next: '[api_url]/&page=2'//indication if the API has a next page previous: null, ////indication if the API has a previous page, if call URL above - it will return [api_url]/&page=1 results: [...] //10 objects for each call, or remaining for the last page } Como sé que solo se devuelven 10 resultados en cada llamada, necesito verificar si el objeto devuelto tiene la next clave y, si la tiene, hacer next llamada y así sucesivamente, hasta que no haya más. Necesito concatenar todos los resultados y eventualmente resolver la Promesa devuelta por la función principal con todos los datos.
Así que probé algo así:
const fetchResource = async({type, search, page}) { const data = {count: 0, results: []} const request = await performFetch({type, search, page}, data).then((data) => { console.log('data?', data) }) console.log('req', request) } const performFetch = async({type, search, page}, result) => { const params = { page } if (search) { params.search = search } await axios.get(`${type}/`, { params }).then(async({data}) => { result.results = [...result.results, ...data.results] result.count = data.count if (data.next) { page += 1 await performFetch({type, search, page}, result) } else { console.log('result', result) return result } }) .catch((err) => { console.error(err) }) } Ahora veo que una vez que llamo a fetchResourche todas las solicitudes se envían y en console.log('result', result) veo los datos concatenados:
{ count: 87, results: [/*all 87 objects*/] } Pero console.log('data?', data) como console.log('req', request) imprimen undefined .
Cuando devuelvo result , traté de devolver Promise.resolve(result) - mismo resultado.
Y no estoy seguro de cómo devolver una Promesa aquí, eso se resolverá una vez que finalicen todas las llamadas a la API y se reciban todos los datos. ¿Qué me estoy perdiendo? ¿Cómo hago para que funcione?
Un par de observaciones con respecto a su código:
No hay necesidad de mezclar la sintaxis async-await con el encadenamiento de promesas, es decir, las llamadas a los métodos then() y catch()
Dentro de la función performFetch , necesita una declaración de return explícita. Actualmente, la función devuelve implícitamente una promesa que cumple con el valor de undefined .
El punto clave aquí es que la función performFetch regresa antes de obtener el resultado de las solicitudes http a la API. No está esperando que se devuelva el resultado de las solicitudes HTTP antes de regresar.
La siguiente es una demostración simple que ilustra cómo puede realizar varias solicitudes y agregar los datos hasta que la API haya devuelto todos los datos.
let counter = 0; function fakeAPI() { return new Promise(resolve => { setTimeout(() => { if (counter < 5) resolve({ counter: counter++ }); else resolve({ done: true }); }, 1000); }); } async function performFetch() { const results = []; // keep calling the `fakeAPI` function // until it returns "{ done = true }" while (true) { const result = await fakeAPI(); if (result.done) break; else results.push(result); } return results; } performFetch().then(console.log).catch(console.log); <small>Wait for 5 seconds</small>Su código se puede reescribir como se muestra a continuación:
const fetchResource = async ({ type, search, page }) => { const data = { count: 0, results: [] }; const result = await performFetch({ type, search, page }, data); console.log(result); }; const performFetch = async ({ type, search, page }, result) => { const params = { page }; if (search) params.search = search; while (true) { const { data } = await axios.get(`${type}/`, { params }); result.results = [...result.results, ...data.results]; result.count = data.count; if (data.next) page += 1; else return result; } }; Idealmente, el código que llama a la función fetchResource debería manejar el error en caso de que falle alguna de las solicitudes HTTP.