Estoy usando la función async.eachLimit para controlar la cantidad máxima de operaciones a la vez.
const { eachLimit } = require("async"); function myFunction() { return new Promise(async (resolve, reject) => { eachLimit((await getAsyncArray), 500, (item, callback) => { // do other things that use native promises. }, (error) => { if (error) return reject(error); // resolve here passing the next value. }); }); } Como puede ver, no puedo declarar la función myFunction como asíncrona porque no tengo acceso al valor dentro de la segunda devolución de llamada de la función eachLimit .
Efectivamente, está utilizando promesas dentro de la función ejecutora del constructor de promesas, por lo que este es el antipatrón del constructor de promesas.
Su código es un buen ejemplo del principal riesgo: no propagar todos los errores de forma segura. Lea por qué allí .
Además, el uso de async / await puede hacer que las mismas trampas sean aún más sorprendentes. Comparar:
let p = new Promise(resolve => { ""(); // TypeError resolve(); }); (async () => { await p; })().catch(e => console.log("Caught: " + e)); // Catches it. con un equivalente async ingenuo (incorrecto):
let p = new Promise(async resolve => { ""(); // TypeError resolve(); }); (async () => { await p; })().catch(e => console.log("Caught: " + e)); // Doesn't catch it!Busque en la consola web de su navegador la última.
El primero funciona porque cualquier excepción inmediata en una función ejecutora del constructor Promise rechaza convenientemente la promesa recién construida (pero dentro de cualquier .then estás solo).
El segundo no funciona porque cualquier excepción inmediata en una función async rechaza la promesa implícita devuelta por la propia función async .
Dado que el valor de retorno de una función ejecutora del constructor de promesas no se utiliza, ¡son malas noticias!
No hay ninguna razón por la que no pueda definir myFunction como async :
async function myFunction() { let array = await getAsyncArray(); return new Promise((resolve, reject) => { eachLimit(array, 500, (item, callback) => { // do other things that use native promises. }, error => { if (error) return reject(error); // resolve here passing the next value. }); }); } Aunque, ¿por qué usar bibliotecas de control de concurrencia obsoletas cuando tiene que await ?
Estoy de acuerdo con las respuestas dadas anteriormente y aún así, a veces es mejor tener asíncrono dentro de su promesa, especialmente si desea encadenar varias operaciones que devuelven promesas y evitar el then().then() infierno. Consideraría usar algo como esto en esa situación:
const operation1 = Promise.resolve(5) const operation2 = Promise.resolve(15) const publishResult = () => Promise.reject(`Can't publish`) let p = new Promise((resolve, reject) => { (async () => { try { const op1 = await operation1; const op2 = await operation2; if (op2 == null) { throw new Error('Validation error'); } const res = op1 + op2; const result = await publishResult(res); resolve(result) } catch (err) { reject(err) } })() }); (async () => { await p; })().catch(e => console.log("Caught: " + e));Promise no es asíncrona, por lo que los linters no muestran errores.await . Sin embargo, un inconveniente es que debe recordar poner try/catch y adjuntarlo para reject .
CREER EN ANTIPATRONES ES UN ANTIPATRÓN
Los lanzamientos dentro de una devolución de llamada de promesa asíncrona se pueden capturar fácilmente.
(async () => { try { await new Promise (async (FULFILL, BREAK) => { try { throw null; } catch (BALL) { BREAK (BALL); } }); } catch (BALL) { console.log ("(A) BALL CAUGHT", BALL); throw BALL; } }) (). catch (BALL => { console.log ("(B) BALL CAUGHT", BALL); });o incluso más simplemente,
(async () => { await new Promise (async (FULFILL, BREAK) => { try { throw null; } catch (BALL) { BREAK (BALL); } }); }) (). catch (BALL => { console.log ("(B) BALL CAUGHT", BALL); });