Me gustaría aclarar este punto, ya que la documentación no es demasiado clara al respecto;
P1: ¿Se Promise.all(iterable)
procesan todas las promesas de forma secuencial o en paralelo? O, más específicamente, ¿es el equivalente a ejecutar promesas encadenadas como
p1.then(p2).then(p3).then(p4).then(p5)....
o se trata de otro tipo de algoritmo donde todos p1
, p2
, p3
, p4
, p5
, etc., están siendo llamados al mismo tiempo (en paralelo) y los resultados son devueltos tan pronto como todos determinación (o se rechaza)?
P2: Si se Promise.all
ejecuta en paralelo, ¿hay alguna forma conveniente de ejecutar un iterable secuencialmente?
Nota : No quiero usar Q o Bluebird, sino todas las especificaciones nativas de ES6.
¿Está
Promise.all(iterable)
cumpliendo todas las promesas?
No, las promesas no se pueden "ejecutar". Comienzan su tarea cuando se están creando (solo representan los resultados) y usted está ejecutando todo en paralelo incluso antes de pasarlos a Promise.all
.
Promise.all
solo espera múltiples promesas. No importa en qué orden se resuelvan o si los cálculos se ejecutan en paralelo.
¿Existe una forma conveniente de ejecutar un iterable secuencialmente?
Si ya tiene sus promesas, no puede hacer mucho pero Promise.all([p1, p2, p3, …])
(que no tiene una noción de secuencia). Pero si tiene una iterable de funciones asincrónicas, puede ejecutarlas secuencialmente. Básicamente necesitas salir de
[fn1, fn2, fn3, …]
a
fn1().then(fn2).then(fn3).then(…)
y la solución para hacerlo es usar Array::reduce
:
iterable.reduce((p, fn) => p.then(fn), Promise.resolve())
await Promise.all(items.map(async item => { await fetchItem(item) }))
Ventajas: más rápido. Todas las iteraciones se iniciarán incluso si una falla.
for (let i = 0; i < items.length; i++) {
await fetchItem(items[i])
}
Ventajas: las variables del bucle se pueden compartir en cada iteración. Se comporta como un código sincrónico imperativo normal.
La respuesta de Bergis me puso en el camino correcto usando Array.reduce.
Sin embargo, para que las funciones devolvieran mis promesas de ejecutar una tras otra, tuve que agregar más anidación.
Mi caso de uso real es una serie de archivos que necesito transferir en orden uno tras otro debido a los límites posteriores ...
Esto es lo que terminé con.
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(() => {
return transferFile(theFile); //function returns a promise
});
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
Como sugieren las respuestas anteriores, use:
getAllFiles().then( (files) => {
return files.reduce((p, theFile) => {
return p.then(transferFile(theFile));
}, Promise.resolve()).then(()=>{
console.log("All files transferred");
});
}).catch((error)=>{
console.log(error);
});
no esperó a que se completara la transferencia antes de iniciar otra y también el texto "Todos los archivos transferidos" llegó incluso antes de que se iniciara la primera transferencia de archivos.
No estoy seguro de qué hice mal, pero quería compartir lo que funcionó para mí.
Editar: Desde que escribí esta publicación, ahora entiendo por qué la primera versión no funcionó. then () espera que una función devuelva una promesa. Por lo tanto, debe pasar el nombre de la función sin paréntesis. Ahora, mi función quiere un argumento, ¡así que necesito envolverme en una función anónima sin argumentos!
NodeJS no ejecuta promesas en paralelo, las ejecuta simultáneamente ya que es una arquitectura de bucle de eventos de un solo subproceso. Existe la posibilidad de ejecutar cosas en paralelo creando un nuevo proceso hijo para aprovechar la CPU de múltiples núcleos.
De hecho, lo que Promise.all
hace es apilar la función de promesas en la cola apropiada (ver arquitectura de bucle de eventos) ejecutarlas al mismo tiempo (llamar a P1, P2, ...) luego esperar cada resultado, luego resolver la Promesa. Todo con todas las promesas resultados. Promise.all fallará a la primera promesa que fallará, a menos que usted mismo haya manejado el rechazo.
Hay una gran diferencia entre paralelo y concurrente, el primero ejecutará diferentes cálculos en un proceso separado exactamente al mismo tiempo y progresarán a su ritmo, mientras que el otro ejecutará los diferentes cálculos uno tras otro sin esperar al anterior. computación para terminar y progresar al mismo tiempo sin depender unos de otros.
Finalmente, para responder a tu pregunta, Promise.all
no se ejecutará ni en paralelo ni secuencialmente sino de manera concurrente.
solo para desarrollar la respuesta de @ Bergi (que es muy concisa, pero difícil de entender;)
Este código ejecutará cada elemento de la matriz y agregará el siguiente 'luego cadena' al final;
function eachorder(prev,order) {
return prev.then(function() {
return get_order(order)
.then(check_order)
.then(update_order);
});
}
orderArray.reduce(eachorder,Promise.resolve());
espero que tenga sentido.
También puede procesar un iterable secuencialmente con una función asincrónica usando una función recursiva. Por ejemplo, dada una matriz a
para procesar con función asincrónica someAsyncFunction()
:
var a = [1, 2, 3, 4, 5, 6]
function someAsyncFunction(n) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("someAsyncFunction: ", n)
resolve(n)
}, Math.random() * 1500)
})
}
//You can run each array sequentially with:
function sequential(arr, index = 0) {
if (index >= arr.length) return Promise.resolve()
return someAsyncFunction(arr[index])
.then(r => {
console.log("got value: ", r)
return sequential(arr, index + 1)
})
}
sequential(a).then(() => console.log("done"))
Al usar async await, se puede ejecutar fácilmente una serie de promesas secuencialmente:
let a = [promise1, promise2, promise3];
async function func() {
for(let i=0; i<a.length; i++){
await a[i]();
}
}
func();
Nota: En la implementación anterior, si se rechaza una promesa, el resto no se ejecutará. Si desea que se ejecuten todas sus promesas, envuelva su await a[i]();
interiortry catch
paralelo
mira este ejemplo
const resolveAfterTimeout = async i => {
return new Promise(resolve => {
console.log("CALLED");
setTimeout(() => {
resolve("RESOLVED", i);
}, 5000);
});
};
const call = async () => {
const res = await Promise.all([
resolveAfterTimeout(1),
resolveAfterTimeout(2),
resolveAfterTimeout(3),
resolveAfterTimeout(4),
resolveAfterTimeout(5),
resolveAfterTimeout(6)
]);
console.log({ res });
};
call();
al ejecutar el código, consolará "CALLED" para las seis promesas y cuando se resuelvan, consolará cada 6 respuestas después del tiempo de espera al mismo tiempo
La respuesta de Bergi me ayudó a sincronizar la llamada. He agregado un ejemplo a continuación donde llamamos a cada función después de que se llama a la función anterior.
function func1 (param1) {
console.log("function1 : " + param1);
}
function func2 () {
console.log("function2");
}
function func3 (param2, param3) {
console.log("function3 : " + param2 + ", " + param3);
}
function func4 (param4) {
console.log("function4 : " + param4);
}
param4 = "Kate";
//adding 3 functions to array
a=[
()=>func1("Hi"),
()=>func2(),
()=>func3("Lindsay",param4)
];
//adding 4th function
a.push(()=>func4("dad"));
//below does func1().then(func2).then(func3).then(func4)
a.reduce((p, fn) => p.then(fn), Promise.resolve());
Puedes hacerlo por bucle for.
promesa de devolución de función asíncrona
async function createClient(client) {
return await Client.create(client);
}
let clients = [client1, client2, client3];
si escribe el siguiente código, el cliente se crea en paralelo
const createdClientsArray = yield Promise.all(clients.map((client) =>
createClient(client);
));
luego, todos los clientes se crean en paralelo. pero si desea crear un cliente secuencialmente, debe usar for loop
const createdClientsArray = [];
for(let i = 0; i < clients.length; i++) {
const createdClient = yield createClient(clients[i]);
createdClientsArray.push(createdClient);
}
luego, todos los clientes se crean secuencialmente.
codificación feliz :)
He estado usando durante de para resolver promesas secuenciales. No estoy seguro de si ayuda aquí, pero esto es lo que he estado haciendo.
async function run() {
for (let val of arr) {
const res = await someQuery(val)
console.log(val)
}
}
run().then().catch()
esto podría responder parte de su pregunta.
sí, puede encadenar una matriz de funciones de devolución de promesa de la siguiente manera ... (esto pasa el resultado de cada función a la siguiente). por supuesto, podría editarlo para pasar el mismo argumento (o ningún argumento) a cada función.
function tester1(a) {
return new Promise(function(done) {
setTimeout(function() {
done(a + 1);
}, 1000);
})
}
function tester2(a) {
return new Promise(function(done) {
setTimeout(function() {
done(a * 5);
}, 1000);
})
}
function promise_chain(args, list, results) {
return new Promise(function(done, errs) {
var fn = list.shift();
if (results === undefined) results = [];
if (typeof fn === 'function') {
fn(args).then(function(result) {
results.push(result);
console.log(result);
promise_chain(result, list, results).then(done);
}, errs);
} else {
done(results);
}
});
}
promise_chain(0, [tester1, tester2, tester1, tester2, tester2]).then(console.log.bind(console), console.error.bind(console));
Me encontré con esta página mientras intentaba resolver un problema en NodeJS: reensamblaje de fragmentos de archivos. Básicamente: tengo una variedad de nombres de archivo. Necesito agregar todos esos archivos, en el orden correcto, para crear un archivo grande. Debo hacer esto de forma asincrónica.
El módulo 'fs' de Node proporciona appendFileSync pero no quería bloquear el servidor durante esta operación. Quería usar el módulo fs.promises y encontrar una manera de encadenar estas cosas. Los ejemplos de esta página no me funcionaron del todo porque en realidad necesitaba dos operaciones: fsPromises.read () para leer en el fragmento del archivo, y fsPromises.appendFile () para hacer una concatenación con el archivo de destino. Tal vez si fuera mejor con javascript, podría haber hecho que las respuestas anteriores funcionen para mí. ;-)
Me encontré con esto ... https://css-tricks.com/why-using-reduce-to-sequentially-resolve-promises-works/ ... y pude hackear juntos una solución funcional.
TLDR:
/**
* sequentially append a list of files into a specified destination file
*/
exports.append_files = function (destinationFile, arrayOfFilenames) {
return arrayOfFilenames.reduce((previousPromise, currentFile) => {
return previousPromise.then(() => {
return fsPromises.readFile(currentFile).then(fileContents => {
return fsPromises.appendFile(destinationFile, fileContents);
});
});
}, Promise.resolve());
};
Y aquí hay una prueba unitaria de jazmín para ello:
const fsPromises = require('fs').promises;
const fsUtils = require( ... );
const TEMPDIR = 'temp';
describe("test append_files", function() {
it('append_files should work', async function(done) {
try {
// setup: create some files
await fsPromises.mkdir(TEMPDIR);
await fsPromises.writeFile(path.join(TEMPDIR, '1'), 'one');
await fsPromises.writeFile(path.join(TEMPDIR, '2'), 'two');
await fsPromises.writeFile(path.join(TEMPDIR, '3'), 'three');
await fsPromises.writeFile(path.join(TEMPDIR, '4'), 'four');
await fsPromises.writeFile(path.join(TEMPDIR, '5'), 'five');
const filenameArray = [];
for (var i=1; i < 6; i++) {
filenameArray.push(path.join(TEMPDIR, i.toString()));
}
const DESTFILE = path.join(TEMPDIR, 'final');
await fsUtils.append_files(DESTFILE, filenameArray);
// confirm "final" file exists
const fsStat = await fsPromises.stat(DESTFILE);
expect(fsStat.isFile()).toBeTruthy();
// confirm content of the "final" file
const expectedContent = new Buffer('onetwothreefourfive', 'utf8');
var fileContents = await fsPromises.readFile(DESTFILE);
expect(fileContents).toEqual(expectedContent);
done();
}
catch (err) {
fail(err);
}
finally {
}
});
});
Espero que esto ayude a alguien.
La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.
Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.
Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.
Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.
Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.
Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?
The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!
¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?
Anteriormente, Kotaku informó que un hotel Godzilla se estaba abriendo en Tokio este abril. Junto al hotel, estaba programada la aparición de una enorme cabeza de 'Zilla, pero todo lo que hemos visto fueron imágenes conceptuales computarizadas.
Foto: Getty Desde que lanzó The Boring Company hace un año, Elon Musk ha mencionado varios sitios de construcción posibles para el negocio de perforación de túneles y ha descartado una vaga referencia a una aprobación gubernamental "verbal" para un túnel Hyperloop que conecta la ciudad de Nueva York y Washington. , CC. Pero ahora sabemos que al menos un alcalde quiere que Musk perfore un agujero debajo de su ciudad.
Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.
Hemos pirateado algunas ciudades industriales en esta columna, como Los Ángeles y Las Vegas. Ahora es el momento de una ciudad militar-industrial-compleja.
El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.
Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon
El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.
El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".
Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.
Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.
“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.
Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.