Así que necesito una forma de ejecutar una función x cantidad de veces en un segundo dado, luego esperar hasta el siguiente segundo para ejecutar el siguiente conjunto. Estoy usando la API de Yelp Fusion para llamar a una 'búsqueda' https://api.yelp.com/v3/search y luego ejecuto una consulta de detalles en cada uno de los resultados de búsqueda: https://api.yelp.com/ v3/negocios/negocio_id .
Entonces, la primera consulta de búsqueda arroja una variedad de negocios como este:
const businesses = response.body.businesses for (business of businesses) { fetchPlaceDetails(business.id) }En teoría, puedo ejecutar fetchPlaceDetails() de forma asíncrona, pero pasar por más de 50 resultados lleva demasiado tiempo. En cambio, me gustaría ejecutar la consulta tal vez 5 veces, esperar un segundo (para superar el límite de frecuencia), ejecutar los siguientes 5, esperar un segundo, ejecutar los siguientes 5, etc.
No estoy seguro de cómo implementar esto, pero creo que debe ser un problema bastante estándar cuando se usan API con límites de velocidad. Además, no estoy seguro, pero en ninguna parte de la documentación veo un límite real de llamada/segundo especificado, pero supongo que son quizás 10 solicitudes/segundo o algo así.
Me gustaría ejecutar la consulta tal vez 5 veces, esperar un segundo (para superar el límite de frecuencia), ejecutar los siguientes 5, esperar un segundo, ejecutar los siguientes 5, etc.
Entonces solo haz eso:
const {businesses} = response.body; for (let i=0; i<businesses.length; i+=5) { await Promise.all([ ...businesses.slice(i, i+5).map(({id}) => fetchPlaceDetails(id)), new Promise(resolve => { setTimeout(resolve, 1000); }) ]); }Esto también garantizará que espere más de un segundo entre los lotes si las 5 solicitudes tardan más que eso.
Aquí hay un método "genérico" que verifica si la matriz de almacenamiento contiene algún dato, si es así, procesa nn cantidad de elementos de la matriz, luego espera ii cantidad de segundos y repite el proceso.
const queue = (() => { let itemsPerStep = 5, //number of items process per step intervalSpeed = 5000, //how long to wait between steps in miliseconds stopWhenDone = true, //when queue list depleted stop the loop prevDate = 0, timer; const list = []; //queue list const commands = { add: item => list.unshift(item), get list() { return list; }, clear: () => list.length = 0, speed: (val = intervalSpeed) => intervalSpeed = val, itemsPerStep: (val = itemNumberPerStep) => itemNumberPerStep = val, stop: () => (timer && console.log("stopped"), timer = clearInterval(timer)), start: (t = true) => (stopWhenDone = t, commands.stop(), timer = setInterval(loop), loop()) }; const loop = () => { const now = new Date(); if (now - prevDate < intervalSpeed) return; if (!list.length) { if (stopWhenDone) commands.stop(); return; } prevDate = now; let res = []; //example result storage for(let i = 0; i < itemsPerStep && list.length; i++) { const value = list.pop(); //get item from the queue list res.push(value); //process value } console.log("processed ids: " + res); } //loop() return commands; })(); //generate ids for(let i = 100; i < 230; i += 11) queue.add(i); queue.start();