Async: Prise en charge de la fonction `async`

Créé le 16 mars 2017  ·  10Commentaires  ·  Source: caolan/async

L'un des éléphants dans la salle est le nouveau support async / await qui est arrivé sur Node et Chrome, et qui arrivera bientôt sur tous les autres navigateurs majeurs. J'ai réfléchi à ce que Async peut faire dans le monde async / await .

Actuellement, nous pouvons adapter les fonctions async en les enveloppant avec asyncify . Étant donné qu'une fonction async n'est essentiellement qu'une fonction qui renvoie une promesse, cet ancien adaptateur peut facilement la convertir en une fonction de type rappel. Cependant, cela conduit à une apparence quelque peu absurde :

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

Cependant, l'une des caractéristiques de la spécification pour les fonctions async est que :

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

Cela permet de détecter facilement les fonctions (natives) async . Nous pourrions utiliser cette technique pour les asyncify automatiquement. L'exemple ci-dessus devient :

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

...qui semble couler beaucoup plus naturellement. Je pense aussi que nous devrions continuer à utiliser les rappels. Si un utilisateur voulait await le résultat, il devrait promisify la fonction, ou pify Async dans son ensemble :

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

La méthode ci-dessus pour détecter les fonctions async ne fonctionne qu'avec les fonctions natives. Je ne pense pas qu'il existe un moyen de détecter les fonctions transpilées de Babel. Nous ne pouvons certainement pas détecter les fonctions normales qui renvoient simplement des promesses, car nous devrions rétroactivement ne pas passer de rappel. Il y aurait une énorme mise en garde sur le fait que cela ne fonctionnerait que sans transpileur dans des environnements très modernes, sinon vous devrez toujours envelopper manuellement avec asyncify .

De plus, il est vrai que de nombreuses méthodes Async n'ont pas de sens avec async / await . La plupart des méthodes de flux de contrôle (sauf pour des choses comme auto et queue ) sont plus facilement répliquées avec des constructions de flux de contrôle natives. map et parallel peuvent être remplacés par Promise.map et Promise.all . Cependant, les fonctions de collecte limitantes seraient très utiles, ainsi que auto et quelques autres. (En outre, autoInject avec des fonctions async est un rêve de flux de contrôle asynchrone !)

enhancement feedback-wanted

Commentaire le plus utile

Y a-t-il une raison de faire Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" ou pouvons-nous faire asyncFn[Symbol.toStringTag] === "AsyncFunction" (semble fonctionner dans FF) ?

C'est juste la façon canonique des spécifications ECMA de le faire. Je suppose qu'en théorie, quelqu'un pourrait écraser asyncFn[Symbol.toStringTag] .

Il en va de même pour la proposition chaque fois que quelqu'un fournit un rappel au format cb(err, arg) nous devrions détecter s'il s'agit d'une AsyncFunction ; s'il s'agit d'une fonction asynchrone, nous devrions appliquer promisify sinon l'utiliser tel quel

Je pense que tu l'as un peu à l'envers. Partout où nous acceptons une fonction itérée acceptant le rappel ( function(args..., callback) {} ), nous devrions vérifier s'il s'agit d'une fonction async , puis la asyncify .

L'exemple await est ce que quelqu'un aurait fait s'il voulait await une méthode Async. Je ne pense pas que nous devrions faire en sorte que les méthodes Async commencent à renvoyer des promesses pour que cela fonctionne - laissez l'utilisateur le faire.

Tous les 10 commentaires

Je vais réfléchir un peu plus à cela, mais j'aimerais poser quelques questions techniques juste pour que je puisse essayer de mieux imaginer à quoi cela ressemble.

Y a-t-il une raison de faire Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" ou pouvons-nous faire asyncFn[Symbol.toStringTag] === "AsyncFunction" (semble fonctionner dans FF) ?

Il en va de même pour la proposition chaque fois que quelqu'un fournit un rappel au format cb(err, arg) , nous devrions détecter s'il s'agit d'un AsyncFunction ; s'il s'agit d'une fonction asynchrone, nous devrions appliquer promisify sinon l'utiliser tel quel

Désolé également, je ne suis pas l'exemple d'attente, si nous détectons que la fonction est un AsyncFunction quels sont les défis de supporter await ?

Y a-t-il une raison de faire Object.getPrototypeOf(asyncFn)[Symbol.toStringTag] === "AsyncFunction" ou pouvons-nous faire asyncFn[Symbol.toStringTag] === "AsyncFunction" (semble fonctionner dans FF) ?

C'est juste la façon canonique des spécifications ECMA de le faire. Je suppose qu'en théorie, quelqu'un pourrait écraser asyncFn[Symbol.toStringTag] .

Il en va de même pour la proposition chaque fois que quelqu'un fournit un rappel au format cb(err, arg) nous devrions détecter s'il s'agit d'une AsyncFunction ; s'il s'agit d'une fonction asynchrone, nous devrions appliquer promisify sinon l'utiliser tel quel

Je pense que tu l'as un peu à l'envers. Partout où nous acceptons une fonction itérée acceptant le rappel ( function(args..., callback) {} ), nous devrions vérifier s'il s'agit d'une fonction async , puis la asyncify .

L'exemple await est ce que quelqu'un aurait fait s'il voulait await une méthode Async. Je ne pense pas que nous devrions faire en sorte que les méthodes Async commencent à renvoyer des promesses pour que cela fonctionne - laissez l'utilisateur le faire.

Implémenté dans #1390 !

Il s'agissait d'un changement de rupture et a cassé notre code déployé. Veuillez réfléchir à deux fois lorsque vous faites de telles choses sans augmenter la version majeure.

PS : merci pour tout le super travail que vous faites avec cette bibliothèque 😄

Tirer! Ce qui a cassé. Pourriez-vous s'il vous plaît créer un ticket avec les détails de la
environnement dans lequel cela n'a pas fonctionné ?
Merci!

Le mer. 5 avr. 2017 à 10 h 18 Manuel Valls Fernández <
[email protected]> a écrit :

Il s'agissait d'un changement de rupture et a cassé notre code déployé. S'il vous plaît, réfléchissez-y à deux fois
lorsque vous faites de telles choses sans augmenter la version majeure.

PS : merci pour tout le super travail que vous faites avec cette bibliothèque 😄


Vous recevez ceci parce que vous avez commenté.
Répondez directement à cet e-mail, consultez-le sur GitHub
https://github.com/caolan/async/issues/1386#issuecomment-291875817 , ou muet
le fil
https://github.com/notifications/unsubscribe-auth/ADUIEPNkTSOVuuiwucBVrH983X6B568Wks5rs6K3gaJpZM4Mf64R
.

D'accord, ça a cassé ma construction aussi...

Une cascade qui appelait une fonction asynchrone qui fonctionnait il y a quelques jours a commencé à échouer avec un "cb n'est pas une fonction" car le rappel asynchrone n'était plus fourni à la fonction.

Désolé, nous avons cassé votre code. Nous n'avions pas anticipé votre cas d'utilisation pour les fonctions async . Je vous recommande de revenir à 2.2.0 ou de refactoriser votre code en return les valeurs dont vous avez besoin, plutôt que d'utiliser des rappels. Malheureusement, le chat est sorti du sac avec cette fonctionnalité, nous ne pouvons donc pas revenir en arrière.

@aearly S'il vous plaît, ne le mentionnez pas !! C'est vraiment gentil de votre part de répondre :1st_place_medal:

@manvalls m'a suggéré une excellente solution qui ne nécessitait pas de restauration. Comme vous utilisez le symbole pour détecter le async dans la déclaration de la fonction, il a pensé à un moyen astucieux de tromper la détection.

Ma cascade utilisait des fonctions exportées à partir d'autres modules, l'une d'entre elles était une async et causait ainsi l'échec.

Donc juste en changeant 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 => {
...
}

À:

... 
/* 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 => {
...
}

Encore merci beaucoup

pouvons-nous utiliser async/wait avec async.autoInject() ?

async.autoInject({

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

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

ne semble pas fonctionner, j'obtiens:

Erreur : les fonctions de tâche autoInject nécessitent des paramètres explicites.
à /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async/dist/async.js:2081:23
à /Users/alexamil/WebstormProjects/nabisco/cdt-now/node_modules/async

@ORESoftware oui, les fonctions async devraient fonctionner avec autoInject . J'ai testé le code que vous avez posté dans Chrome, et il a fonctionné. J'ai reçu un ReferenceError lors du rappel final car conn1 et conn2 sont undefined . Après l'avoir changé en

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

ça fonctionne bien. Cependant, nous ne prenons pas en charge les fonctions async transpilées. Êtes-vous en train de transpiler votre code ?

Cette page vous a été utile?
0 / 5 - 0 notes