Comment savoir si une fonction est asynchrone?
je dois passer une fonction à une autre, et l'exécuter comme un callback. Le problème est que parfois cette fonction est async, comme:
async function() {
// Some async actions
}
Si je veux exécuter await callback()
ou callback()
selon le type de fonction qu'il reçoit.
Est-il un moyen de connaître le type de la fonction??
5 réponses
Native async
fonctions peuvent être identifiable quand être converties en chaînes :
asyncFn[Symbol.toStringTag] === 'AsyncFunction'
ou par AsyncFunction
constructeur:
const AsyncFunction = (async () => {}).constructor;
asyncFn instanceof AsyncFunction === true
cela ne fonctionnera pas avec la sortie Babel/TypeScript, parce que asyncFn
est une fonction régulière en code transpilé, c'est une instance de Function
ou GeneratorFunction
, pas AsyncFunction
. Pour s'assurer qu'il ne donnera pas faux positifs pour le générateur et régulier des fonctions dans transpiled code:
const AsyncFunction = (async () => {}).constructor;
const GeneratorFunction = (function* () => {}).constructor;
(asyncFn instanceof AsyncFunction && AsyncFunction !== Function && AsyncFunction !== GeneratorFunction) === true
la question fait évidemment référence à la mise en œuvre Babel de la fonction async
, qui s'appuie sur transform-async-to-generator
pour transpiler async
à des fonctions de générateur, peut également utiliser transform-regenerator
pour transpiler générateur à des fonctions régulières.
le résultat de async
appel de fonction est une promesse. selon la proposition , une promesse ou une non-promesse peut être transmise à await
, donc await callback()
est universel.
async
utilisent les promesses natives en interne et ne saisissent pas global Promise
si son implémentation a été modifiée:
let NativePromise = Promise;
Promise = CustomPromiseImplementation;
Promise.resolve() instanceof Promise === true
(async () => {})() instanceof Promise === false;
(async () => {})() instanceof NativePromise === true;
cela peut affecter le comportement de la fonction (ceci est un problème connu pour angle et Zone.js promesse de la mise en œuvre ). Même alors, il est préférable de détecter que la valeur de retour de la fonction n'est pas attendue Promise
instance au lieu de détecter qu'une fonction est async
, parce que le même problème est applicable à toute fonction qui utilise l'implémentation de promesse alternative, pas seulement async
( la solution à ce problème angulaire est d'envelopper async
valeur de retour avec Promise.resolve
).
TL;DR: async
les fonctions ne devraient pas être distinguées des fonctions régulières qui rendent des promesses. ils ne devraient certainement pas être distingués dans une situation comme celle-ci. Il n'y a aucun moyen fiable et aucune raison de détecter les fonctions async
transposées non natives.
les deux @rnd et @estus sont corrects.
mais pour répondre à la question avec une solution de travail réelle ici vous allez
function isAsync (func) {
const string = func.toString().trim();
return !!(
// native
string.match(/^async /) ||
// babel (this may change, but hey...)
string.match(/return _ref[^\.]*\.apply/)
// insert your other dirty transpiler check
// there are other more complex situations that maybe require you to check the return line for a *promise*
);
}
c'est une question très valable, et je suis contrarié que quelqu'un l'ait rejeté. La principale usecase pour ce type de vérification est une bibliothèque/framework/decorators.
ce sont les premiers jours, et nous ne devrions pas baisser la note valide questions.
TL; DR
brève réponse: utiliser instaceof
après exposition AsyncFunction
- voir ci-dessous.
longue réponse: ne faites pas cela-voir ci-dessous.
Comment le faire", 1519280920"
vous pouvez détecter si une fonction a été déclarée avec le async
mot-clé
quand vous créez une fonction, elle montre que C'est une fonction de type:
> f1 = function () {};
[Function: f1]
vous pouvez le tester avec l'opérateur instanceof
:
> f1 instanceof Function
true
quand vous créez une fonction async, elle montre que c'est un type AsyncFunction:
> f2 = async function () {}
[AsyncFunction: f2]
donc on peut s'attendre à ce qu'il puisse être testé avec instanceof
ainsi:
> f2 instanceof AsyncFunction
ReferenceError: AsyncFunction is not defined
pourquoi? Parce que la fonction asynchrone n'est pas un objet global. Voir les documents:
même si, comme vous pouvez le voir, il est répertorié sous Reference/Global_Objects
...
si vous avez besoin d'un accès facile au AsyncFunction
alors vous pouvez utiliser mon unexposed
module:
pour obtenir soit un local variable:
const { AsyncFunction } = require('unexposed');
ou pour ajouter un global AsyncFunction
à côté d'autres global objects:
require('unexposed').addGlobals();
et maintenant les travaux ci-dessus comme prévu:
> f2 = async function () {}
[AsyncFunction: f2]
> f2 instanceof AsyncFunction
true
Pourquoi vous ne devriez pas le faire
le code ci-dessus va tester si la fonction a été créée avec le mot-clé async
mais gardez à l'esprit que ce qui est vraiment important n'est pas comment une fonction a été créée mais si oui ou non une fonction retourne une promesse.
partout où vous pouvez utiliser cette fonction "async":
const f1 = async () => {
// ...
};
vous pouvez également utiliser ceci:
const f2 = () => new Promise((resolve, reject) => {
});
même s'il n'a pas été créé avec le mot-clé async
et ne sera donc pas apparié avec instanceof
ou avec toute autre méthode affichée dans les autres réponses .
en particulier, considérez ceci:
const f1 = async (x) => {
// ...
};
const f2 = () => f1(123);
le f2
est juste f1
avec un argument hardcodé et il ne fait pas beaucoup de sens d'ajouter async
ici, même si le résultat sera autant "async" que f1
à tous les égards.
résumé
il est donc possible de vérifier si une fonction a été créée avec le mot-clé async
, mais utilisez-le avec prudence parce que vous lorsque vous le vérifiez, alors très probablement vous faites quelque chose de mal.
il semble que await
puisse aussi être utilisé pour des fonctions normales. Je ne sais pas si cela peut être considéré comme une "bonne pratique" , mais le voici:
async function asyncFn() {
// await for some async stuff
return 'hello from asyncFn'
}
function syncFn() {
return 'hello from syncFn'
}
async function run() {
console.log(await asyncFn()) // 'hello from asyncFn'
console.log(await syncFn()) // 'hello from syncFn'
}
run()
je préfère cette voie simple:
theFunc.constructor.name == 'AsyncFunction'