Por lo que tengo entendido, en ES7 / ES2016, poner múltiples await
en el código funcionará de manera similar a encadenar .then()
con promesas, lo que significa que se ejecutarán una tras otra en lugar de en paralelo. Entonces, por ejemplo, tenemos este código:
await someCall();
await anotherCall();
¿Entiendo correctamente que anotherCall()
se llamará solo cuando someCall()
esté completo? ¿Cuál es la forma más elegante de llamarlos en paralelo?
Quiero usarlo en Node, así que tal vez haya una solución con la biblioteca asíncrona.
EDITAR: No estoy satisfecho con la solución proporcionada en esta pregunta: Ralentización debido a la espera no paralela de promesas en generadores asíncronos , porque usa generadores y estoy preguntando sobre un caso de uso más general.
Puede esperar en Promise.all()
:
await Promise.all([someCall(), anotherCall()]);
Para almacenar los resultados:
let [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
Tenga en cuenta que Promise.all
falla rápido, lo que significa que tan pronto como una de las promesas que se le hicieron se rechaza, entonces todo se rechaza.
const happy = (v, ms) => new Promise((resolve) => setTimeout(() => resolve(v), ms))
const sad = (v, ms) => new Promise((_, reject) => setTimeout(() => reject(v), ms))
Promise.all([happy('happy', 100), sad('sad', 50)])
.then(console.log).catch(console.log) // 'sad'
Si, en cambio, desea esperar a que todas las promesas se cumplan o se rechacen, puede usar Promise.allSettled
. Tenga en cuenta que Internet Explorer no es compatible de forma nativa con este método.
const happy = (v, ms) => new Promise((resolve) => setTimeout(() => resolve(v), ms))
const sad = (v, ms) => new Promise((_, reject) => setTimeout(() => reject(v), ms))
Promise.allSettled([happy('happy', 100), sad('sad', 50)])
.then(console.log) // [{ "status":"fulfilled", "value":"happy" }, { "status":"rejected", "reason":"sad" }]
TL; DR
Utilice Promise.all
para las llamadas a funciones paralelas, los comportamientos de respuesta no son correctos cuando se produce el error.
Primero, ejecute todas las llamadas asincrónicas a la vez y obtenga todos los Promise
objetos. En segundo lugar, utilícelo await
en los Promise
objetos. De esta manera, mientras esperas Promise
a que se resuelva el primero, las otras llamadas asincrónicas siguen progresando. En general, solo esperará el tiempo que dure la llamada asincrónica más lenta. Por ejemplo:
// Begin first call and store promise without waiting
const someResult = someCall();
// Begin second call and store promise without waiting
const anotherResult = anotherCall();
// Now we await for both results, whose async processes have already been started
const finalResult = [await someResult, await anotherResult];
// At this point all calls have been resolved
// Now when accessing someResult| anotherResult,
// you will have a value instead of a promise
Ejemplo de JSbin: http://jsbin.com/xerifanima/edit?js,console
Advertencia: no importa si las await
llamadas están en la misma línea o en líneas diferentes, siempre que la primera await
llamada ocurra después de todas las llamadas asincrónicas. Vea el comentario de JohnnyHK.
Actualización: esta respuesta tiene un tiempo diferente en el manejo de errores de acuerdo con la Esperando más de una operación de espera simultánea , NO arroja el error cuando ocurre el error, pero después de que se ejecutan todas las promesas. Comparo el resultado con el consejo de @ jonny:, [result1, result2] = Promise.all([async1(), async2()])
verifique el siguiente fragmento de código
const correctAsync500ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 500, 'correct500msResult');
});
};
const correctAsync100ms = () => {
return new Promise(resolve => {
setTimeout(resolve, 100, 'correct100msResult');
});
};
const rejectAsync100ms = () => {
return new Promise((resolve, reject) => {
setTimeout(reject, 100, 'reject100msError');
});
};
const asyncInArray = async (fun1, fun2) => {
const label = 'test async functions in array';
try {
console.time(label);
const p1 = fun1();
const p2 = fun2();
const result = [await p1, await p2];
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
const asyncInPromiseAll = async (fun1, fun2) => {
const label = 'test async functions with Promise.all';
try {
console.time(label);
let [value1, value2] = await Promise.all([fun1(), fun2()]);
console.timeEnd(label);
} catch (e) {
console.error('error is', e);
console.timeEnd(label);
}
};
(async () => {
console.group('async functions without error');
console.log('async functions without error: start')
await asyncInArray(correctAsync500ms, correctAsync100ms);
await asyncInPromiseAll(correctAsync500ms, correctAsync100ms);
console.groupEnd();
console.group('async functions with error');
console.log('async functions with error: start')
await asyncInArray(correctAsync500ms, rejectAsync100ms);
await asyncInPromiseAll(correctAsync500ms, rejectAsync100ms);
console.groupEnd();
})();
Actualizar:
La respuesta original hace que sea difícil (y en algunos casos imposible) manejar correctamente los rechazos de promesas. La solución correcta es utilizar Promise.all
:
const [someResult, anotherResult] = await Promise.all([someCall(), anotherCall()]);
Respuesta original:
Solo asegúrese de llamar a ambas funciones antes de esperar una de ellas:
// Call both functions
const somePromise = someCall();
const anotherPromise = anotherCall();
// Await both promises
const someResult = await somePromise;
const anotherResult = await anotherPromise;
Hay otra forma sin Promise.all () de hacerlo en paralelo:
Primero, tenemos 2 funciones para imprimir números:
function printNumber1() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number1 is done");
resolve(10);
},1000);
});
}
function printNumber2() {
return new Promise((resolve,reject) => {
setTimeout(() => {
console.log("Number2 is done");
resolve(20);
},500);
});
}
Esto es secuencial:
async function oneByOne() {
const number1 = await printNumber1();
const number2 = await printNumber2();
}
//Output: Number1 is done, Number2 is done
Esto es paralelo:
async function inParallel() {
const promise1 = printNumber1();
const promise2 = printNumber2();
const number1 = await promise1;
const number2 = await promise2;
}
//Output: Number2 is done, Number1 is done
Esto se puede lograr con Promise.allSettled () , que es similar Promise.all()
pero sin el comportamiento rápido de fallas.
async function failure() {
throw "Failure!";
}
async function success() {
return "Success!";
}
const [failureResult, successResult] = await Promise.allSettled([failure(), success()]);
console.log(failureResult); // {status: "rejected", reason: "Failure!"}
console.log(successResult); // {status: "fulfilled", value: "Success!"}
Nota : esta es una característica de vanguardia con soporte de navegador limitado, por lo que recomiendo encarecidamente incluir un polyfill para esta función.
He creado una esencia probando algunas formas diferentes de resolver promesas, con resultados. Puede resultar útil ver las opciones que funcionan.
En mi caso, tengo varias tareas que quiero ejecutar en paralelo, pero necesito hacer algo diferente con el resultado de esas tareas.
function wait(ms, data) {
console.log('Starting task:', data, ms);
return new Promise(resolve => setTimeout(resolve, ms, data));
}
var tasks = [
async () => {
var result = await wait(1000, 'moose');
// do something with result
console.log(result);
},
async () => {
var result = await wait(500, 'taco');
// do something with result
console.log(result);
},
async () => {
var result = await wait(5000, 'burp');
// do something with result
console.log(result);
}
]
await Promise.all(tasks.map(p => p()));
console.log('done');
Y la salida:
Starting task: moose 1000
Starting task: taco 500
Starting task: burp 5000
taco
moose
burp
done
esperar Promise.all ([someCall (), anotherCall ()]); como ya se mencionó, actuará como un hilo de cerca (muy común en código paralelo como CUDA), por lo tanto, permitirá que todas las promesas se ejecuten sin bloquearse entre sí, pero evitará que la ejecución continúe hasta que TODAS se resuelvan.
Otro enfoque que vale la pena compartir es el async de Node.js que también te permitirá controlar fácilmente la cantidad de simultaneidad que suele ser deseable si la tarea está directamente vinculada al uso de recursos limitados como llamada a API, operaciones de E / S, etc.
// create a queue object with concurrency 2
var q = async.queue(function(task, callback) {
console.log('Hello ' + task.name);
callback();
}, 2);
// assign a callback
q.drain = function() {
console.log('All items have been processed');
};
// add some items to the queue
q.push({name: 'foo'}, function(err) {
console.log('Finished processing foo');
});
q.push({name: 'bar'}, function (err) {
console.log('Finished processing bar');
});
// add some items to the queue (batch-wise)
q.push([{name: 'baz'},{name: 'bay'},{name: 'bax'}], function(err) {
console.log('Finished processing item');
});
// add some items to the front of the queue
q.unshift({name: 'bar'}, function (err) {
console.log('Finished processing bar');
});
Créditos al autor del artículo de Medium ( leer más )
// A generic test function that can be configured
// with an arbitrary delay and to either resolve or reject
const test = (delay, resolveSuccessfully) => new Promise((resolve, reject) => setTimeout(() => {
console.log(`Done ${ delay }`);
resolveSuccessfully ? resolve(`Resolved ${ delay }`) : reject(`Reject ${ delay }`)
}, delay));
// Our async handler function
const handler = async () => {
// Promise 1 runs first, but resolves last
const p1 = test(10000, true);
// Promise 2 run second, and also resolves
const p2 = test(5000, true);
// Promise 3 runs last, but completes first (with a rejection)
// Note the catch to trap the error immediately
const p3 = test(1000, false).catch(e => console.log(e));
// Await all in parallel
const r = await Promise.all([p1, p2, p3]);
// Display the results
console.log(r);
};
// Run the handler
handler();
/*
Done 1000
Reject 1000
Done 5000
Done 10000
*/
Si bien la configuración de p1, p2 y p3 no los ejecuta estrictamente en paralelo, no retrasan ninguna ejecución y puede atrapar errores contextuales con una captura.
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.