Async: Compatibilidad con la función `async`

Creado en 16 mar. 2017  ·  10Comentarios  ·  Fuente: caolan/async

Uno de los elefantes en la sala es el nuevo soporte async / await que ha llegado a Node y Chrome, y pronto llegará a todos los demás navegadores importantes. He estado pensando en lo que Async puede hacer en el mundo async / await .

Actualmente, podemos adaptar las funciones async envolviéndolas con asyncify . Dado que una función async es esencialmente solo una función que devuelve una Promesa, ese adaptador antiguo puede convertirla fácilmente en una función de estilo de devolución de llamada. Sin embargo, conduce a un aspecto un tanto absurdo:

async.mapLimit(arr, 10, async.asyncify(async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}), done);

Sin embargo, una de las características de la especificación para las funciones async es que:

Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction"

Esto brinda una manera de detectar fácilmente funciones (nativas) async . Podríamos usar esta técnica para asyncify automáticamente. El ejemplo anterior se convierte en:

async.mapLimit(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
}, done);

...que parece fluir mucho más naturalmente. También creo que deberíamos seguir usando devoluciones de llamada. Si un usuario quisiera await el resultado, tendría que promisify la función, o pify Async como un todo:

let result = await pify(async.mapLimit)(arr, 10, async (val) => {
  let foo = await doSomething(val);
  //...
 return bar;
});

El método anterior para detectar funciones async solo funciona con funciones nativas. No creo que haya una manera de detectar las funciones transpiladas de Babel. Ciertamente, no podemos detectar funciones normales que simplemente devuelvan Promesas, porque tendríamos que retroactivamente no pasar una devolución de llamada. Habría una gran advertencia de que esto solo funcionaría sin un transpilador en entornos muy modernos, de lo contrario, aún debe envolver manualmente con asyncify .

Además, es cierto que muchos métodos Async no tienen sentido con async / await . La mayoría de los métodos de flujo de control (a excepción de cosas como auto y queue ) se replican más fácilmente con construcciones de flujo de control nativas. map y parallel se pueden reemplazar con Promise.map y Promise.all . Sin embargo, las funciones de cobro limitado serían muy útiles, así como auto y algunas otras. (¡Además, autoInject con funciones async es un sueño de flujo de control asíncrono!)

enhancement feedback-wanted

Comentario más útil

¿Hay alguna razón para hacer Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" o podemos hacer asyncFn[Symbol.toStringTag] === "AsyncFunction" (parece funcionar en FF)?

Esa es solo la forma canónica de especificación ECMA para hacerlo. Supongo que, en teoría, alguien podría sobrescribir asyncFn[Symbol.toStringTag] .

También lo es la propuesta cada vez que alguien proporciona una devolución de llamada del formato cb (err, arg) debemos detectar si es una función asíncrona; si es una función asíncrona, deberíamos aplicar promisify; de lo contrario, úsela como está

Creo que lo tienes un poco al revés. Siempre que aceptemos una función iterativa de aceptación de devolución de llamada ( function(args..., callback) {} ), debemos verificar si es una función async y luego asyncify .

El ejemplo await es lo que alguien habría hecho si quisiera await un método asíncrono. No creo que debamos hacer que los métodos Async comiencen a devolver promesas para que eso funcione; déjelo para que lo haga el usuario.

Todos 10 comentarios

Voy a reflexionar sobre esto un poco más, pero me gustaría hacer un par de preguntas técnicas solo para poder imaginarme mejor cómo se ve esto...

¿Hay alguna razón para hacer Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" o podemos hacer asyncFn[Symbol.toStringTag] === "AsyncFunction" (parece funcionar en FF)?

Así es la propuesta cada vez que alguien proporciona una devolución de llamada del formato cb(err, arg) , debemos detectar si es un AsyncFunction ; si se trata de una función asíncrona, deberíamos aplicar promisify ; de lo contrario, utilícela tal cual

También lo siento, no estoy siguiendo el ejemplo de espera, si detectamos que la función es AsyncFunction ¿cuáles son los desafíos de admitir await ?

¿Hay alguna razón para hacer Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" o podemos hacer asyncFn[Symbol.toStringTag] === "AsyncFunction" (parece funcionar en FF)?

Esa es solo la forma canónica de especificación ECMA para hacerlo. Supongo que, en teoría, alguien podría sobrescribir asyncFn[Symbol.toStringTag] .

También lo es la propuesta cada vez que alguien proporciona una devolución de llamada del formato cb (err, arg) debemos detectar si es una función asíncrona; si es una función asíncrona, deberíamos aplicar promisify; de lo contrario, úsela como está

Creo que lo tienes un poco al revés. Siempre que aceptemos una función iterativa de aceptación de devolución de llamada ( function(args..., callback) {} ), debemos verificar si es una función async y luego asyncify .

El ejemplo await es lo que alguien habría hecho si quisiera await un método asíncrono. No creo que debamos hacer que los métodos Async comiencen a devolver promesas para que eso funcione; déjelo para que lo haga el usuario.

¡Implementado en #1390!

Este fue un cambio importante y rompió nuestro código implementado. Por favor, piénselo dos veces cuando haga tales cosas sin aumentar la versión principal.

PD: gracias por todo el gran trabajo que estás haciendo con esta biblioteca 😄

¡Disparo! Que se rompió. ¿Podría crear un ticket con los detalles de la
entorno esto no funcionó en?
¡Gracias!

El miércoles 5 abr 2017 a las 10:18 Manuel Valls Fernández <
[email protected]> escribió:

Este fue un cambio importante y rompió nuestro código implementado. Por favor piénsalo dos veces
al hacer tales cosas sin aumentar la versión principal.

PD: gracias por todo el gran trabajo que estás haciendo con esta biblioteca 😄


Estás recibiendo esto porque comentaste.
Responda a este correo electrónico directamente, véalo en GitHub
https://github.com/caolan/async/issues/1386#issuecomment-291875817 , o silenciar
la amenaza
https://github.com/notifications/unsubscribe-auth/ADUIEPNkTSOVuuiwucBVrH983X6B568Wks5rs6K3gaJpZM4Mf64R
.

De acuerdo, también rompió mi construcción...

Una cascada que estaba llamando a una función asíncrona que funcionó hace unos días comenzó a fallar con un "cb no es una función" porque la devolución de llamada asíncrona ya no se proporcionaba a la función.

Lo siento, rompimos tu código. No anticipamos su caso de uso para las funciones async . Recomendaría volver a 2.2.0 o refactorizar su código a return los valores que necesita, en lugar de usar devoluciones de llamada. Desafortunadamente, el gato está fuera de la bolsa con esta función, por lo que no podemos retroceder.

@aearly ¡ Por favor, no lo menciones! Es muy amable de tu parte responder :1st_place_medal:

@manvalls me insinuó una gran solución que no requería revertir. Como está usando el símbolo para detectar el async en la declaración de la función, pensó en una forma inteligente de engañar a la detección.

Mi cascada estaba usando funciones exportadas de otros módulos, uno de ellos era async y, por lo tanto, causaba la falla.

Así que simplemente cambiando de:

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: doThatAsync  
}; 

...
async.waterfall([
  services.doThis,
  services.doThat,  // fails with "cb is not a function"
], err => {
...
}

A:

... 
/* services module */
function doThis(param, cb) {
...
}

async function doThatAsync(param, cb) {
...
}

module.exports = {
  doThis: doThis,
  doThat: (...args) => doThatAsync(..args)   // cheating the detection
}; 

...
async.waterfall([
  services.doThis,
  services.doThat, /* it works!!! */
], err => {
...
}

De nuevo, muchas gracias

¿Podemos usar async/await con async.autoInject()?

async.autoInject({

    conn1: async function () {
      return conn1;
    },

    conn2: async function () {
      return conn2;
    },
});

no parece funcionar, obtengo:

Error: las funciones de tareas de autoInject requieren parámetros explícitos.
en /Usuarios/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async/dist/async.js:2081:23
en /Usuarios/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async

@ORESoftware sí, las funciones async deberían funcionar con autoInject . Probé el código que publicaste en Chrome y se ejecutó. Recibí ReferenceError en la devolución de llamada final como conn1 y conn2 son undefined . Después de cambiarlo a

async.autoInject({
    conn1: async function () {
      return 'foo'
    },
    conn2: async function () {
      return 'bar'
    },
})

funciona bien. Sin embargo, no admitimos las funciones async transpiladas. ¿Está transpilando su código?

¿Fue útil esta página
0 / 5 - 0 calificaciones