javascript - promises - Paralelismo limitado con async/await en Typecript/ES7
typescript delay (3)
He estado experimentando un poco con Typecript, pero ahora estoy un poco atascado en cómo usar async / wait.
Estoy insertando un montón de registros en una base de datos, y necesito obtener la lista de ID que devuelve cada inserción. El siguiente ejemplo simplificado funciona en general, pero no es tan elegante como me gustaría y es completamente secuencial.
async function generatePersons() {
const names = generateNames(firstNames, lastNames);
let ids = []
for (let name of names) {
const id = await db("persons").insert({
first_name: name.firstName,
last_name: name.lastName,
}).returning(''id'');
ids.push(id[0])
}
return ids
}
Traté de usar el
map
para evitar crear la lista de
ids
manualmente, pero pude hacer que esto funcione.
Lo que también me gustaría tener es una cantidad limitada de paralelismo. Por lo tanto, mis llamadas asincrónicas deben realizarse en paralelo hasta cierto límite, por ejemplo, solo me gustaría tener 10 solicitudes abiertas, pero no más.
¿Existe una forma razonablemente elegante de lograr este tipo de paralelismo limitado con async / wait en Typecript o Javascript ES7? ¿O estoy tratando de hacer que esta función haga algo para lo que no estaba destinada?
PD: Sé que hay métodos de inserción masiva para bases de datos, este ejemplo es un poco artificial, ya que podría usarlos para solucionar este problema específico. Pero me hizo preguntarme sobre el caso general en el que no tengo métodos masivos predefinidos disponibles, por ejemplo, con solicitudes de red
¿Existe una forma razonablemente elegante de lograr este tipo de paralelismo limitado con async / await en Typecript o Javascript ES7
Tendrás que usar
Promise.all
.
es decir, recopilar todas las promesas en una matriz y
await Promise.all([all,the,stuff])
.
Más
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
async-parallel biblioteca async-parallel que ofrece varias funciones auxiliares que facilitan la realización de operaciones paralelas. Al usar esta biblioteca, su código podría verse así ...
async function generatePersons(): Promise<number[]> {
const names = generateNames(firstNames, lastNames);
return await Parallel.map(names, async (name) =>
await db("persons").insert({
first_name: name.firstName,
last_name: name.lastName,
}).returning(''id''));
}
Si desea limitar el número de instancias para decir cuatro a la vez, simplemente puede hacer lo siguiente ...
Parallel.concurrency = 4;
Promise.all
le permitirá esperar a que todas las solicitudes dejen de finalizar, sin bloquear su creación.
Sin embargo, parece que a veces quieres bloquear. Específicamente, sonó como si quisiera limitar el número de solicitudes en vuelo en un momento dado. Aquí hay algo que preparé (¡pero no lo he probado completamente!)
async function asyncThrottledMap<T, U>(maxCount: number, array: T[], f: (x: T) => Promise<U>) {
let inFlight = new Set<Promise<U>>();
const result: Promise<U>[] = [];
// Sequentially add a Promise for each operation.
for (let elem of array) {
// Wait for any one of the promises to complete if there are too many running.
if (inFlight.size >= maxCount) {
await Promise.race(inFlight);
}
// This is the Promise that the user originally passed us back.
const origPromise = f(elem);
// This is a Promise that adds/removes from the set of in-flight promises.
const handledPromise = wrap(origPromise);
result.push(handledPromise);
}
return Promise.all(result);
async function wrap(p: Promise<U>) {
inFlight.add(p);
const result = await p;
inFlight.delete(p);
return result;
}
}
Arriba,
inFlight
es un conjunto de operaciones que se están llevando a cabo actualmente.
El
result
es una serie de
Promise
s
envueltos
.
Cada una de esas promesas envueltas básicamente agrega o elimina operaciones del conjunto de operaciones
inFlight
.
Si hay demasiadas operaciones en vuelo, esto usa
Promise.race
para que se
Promise.race
cualquiera de las operaciones en vuelo.
Espero que eso ayude.