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??

25
demandé sur Felix Kling 2016-07-21 18:32:19

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.

"1519260920 Il n'y a que quelques cas où cela peut être nécessaire. Par exemple, les fonctions natives 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.

31
répondu estus 2018-07-09 13:08:07

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.

9
répondu Chad Scira 2016-12-19 14:50:40

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.

1
répondu rsp 2018-03-08 06:34:20

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()
1
répondu gyo 2018-07-25 11:32:38

je préfère cette voie simple:

theFunc.constructor.name == 'AsyncFunction'
1
répondu Alexander 2018-08-19 19:33:03