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 !)
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 faireasyncFn[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 ?
Commentaire le plus utile
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]
.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 fonctionasync
, puis laasyncify
.L'exemple
await
est ce que quelqu'un aurait fait s'il voulaitawait
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.