-
Notifications
You must be signed in to change notification settings - Fork 106
Programmatically check if function is async #78
Comments
function isAsync(fn) {
return fn.constructor.name === 'AsyncFunction';
} See: https://tc39.github.io/ecmascript-asyncawait/#async-function-constructor-properties |
Please do not do this. Any function that returns a promise is an async function. |
@domenic As understand the issue is that you can't determine return value ahead of time. |
And
in general, it's not quite valid statement, e.g.: function foo(bar) {
if (bar)
return new Promise(resolve => ...);
// NOTE: please, never do this!
return null;
} |
async function x() {}
function y() { return Promise.resolve(); }
function z() { return y() || x(); } Good luck! |
Yes, @zxqfox has illustrated the issue precisely. There is no behavior difference between his x, y, and z. Every library that develops around async functions should allow both x, y, and z to be used as an async function. If it does not, it is a bad library. In JavaScript, this kind of type checking is in general an antipattern. You should instead proceed by assuming that what you are given is the correct type. Your program will fail, correctly, if it is not. |
Yeah, my point is to understand how the function will run ahead of calling it. In theory you can have a library that handles passed async functions differently than normal functions. For example passing different arguments to them when they are called, for whatever reason. As I understand async functions always returns a promise? It is a nice guarantee that is only valuable if you can actually check for it. Historically things that are considered bad practice can suddenly become useful when devs get creative. Like Google with Angular. Use of Eval for mixing html attributes with javascript and toString of function name for dependency injection are at its core really bad practices, and personally I think it is crazy, but it has served a purpose :-) Anyways, just saying that if it is not a technical reason, but because it is considered a bad practice today, maybe it will limit some good (or bad) idea worth exploring later on. |
It is bad practice for a technical reason, as explained above. There is no difference between async functions and other promise returning functions, so libraries that try to distinguish them are technically unsound. |
Okay, cool, thanks for taking the time to answer :-) |
@domenic If it's good practice is there any reason to distinguish async functions with different ctor type? AFAIK arrow's |
@inikulin it's so that you can do |
@domenic Right. Thank you for the clarification. |
@domenic If I get it right from the TC discussion |
@inikulin correct, just like GeneratorFunction - however, both are accessible via const GeneratorFunction = (function* () {}).constructor;
const AsyncFunction = (async function () {}).constructor; |
Hey, just ran into this issue:
I currently have a use case where I need to serialize functions in order to send them to run on another VM instance - it's the first time I need such a distinction to be fair. |
I am doing something similar generating new code to replicate an existing class dynamically (written by a user). The code does not run, so whether or not it returns a Promise is irrelevant, what matters is whether the await keyword is supported inside it. |
In general I agree with this, however there are some valid use cases, e.g. see: spheredev/neosphere#251
|
@fatcerberus neither can arrow functions. Try checking the .prototype property? |
Indeed, but I don't expect anyone to export an arrow function as the main entry point (and if they do I'm fine with it not working). 😄 Same goes for generator functions. In any case I already know I can check the |
Try calling it with |
No good, if the exception turns out to originate within the function code itself you've now caused unwanted side effects. I guess you could compare the error messages to decide whether or not to retry but that seems like a really ugly hack just begging for regressions. Testing |
You should not use async function as a proxy for "can be called with new". Use an actual isConstructor check, e.g. https://esdiscuss.org/topic/isconstructor#content-11. |
@domenic Thanks, wasn’t aware there was a side-effect free way to do that without explicit support in the JS-engine’s API. |
Maybe, but that doesn't answer the question. It only detracts from it. It is perfectly valid for some API to say "if you pass an async function, this tool will do such and such, otherwise it will do such and such". I, for example, and making an ES5-based class inheritance tool, and I'd like to throw an error if the user provides an |
@trusktr your only options are to extract the constructor and use |
|
@zhujun24 |
@ljharb It has nothing to do with function name |
But... Your indexOf check is specifically looking for the position of the function name... |
Oooh. |
@zhujun24 indeed, as has been noted up thread, there is no good way to detect one. |
I stumbled upon this trying to execute an uknown function received as a parameter. How I finally solved it was forcing it to be async so I could always execute it with await.
It may help someone |
Maybe this is part of the spec, but I was not able to find it in the text.
Will it be possible to check if a function is an async function? This would be beneficial developing libraries around async functions. Just to make my point clear with pseudo code:
The text was updated successfully, but these errors were encountered: