It would be weird for async functions to be synchronous wouldn't it?
Also the consumer is not required to use await with a called async function. They can use .then on it, or pass it around to other functions that consumes promises. Or, you could pass the async function to decorators that consume promise returning functions. Using experimental decorator syntax:
@debouncePromise
async function() {
...
}
Yes it is a trade off of performance for convenience and consistency.
Weird: Depends. I think that an async function might sometimes complete synchronously is not weird - it can happen in many scenarios where the least common denominator is "The function might sometimes take a long time and therfore has to be async". Having a different return type depending on the taken path (Value or Promise<Value>) is definitely weird and should not be encouraged (although supported by JS). I'm therefore in favor of the decision that an async function always returns a Promise - I just wanted to know if anybody has more insight on how the decision was taken and if the performance impact has been considered.
Thanks for bringing up the issue around that an await on a value will wrap it into a promise before! That means even the following "workaround" would not work:
function getFromCacheOrRemote() {
if (random()) {
return "Got it";
} else {
return DoSomethingLongRunnningWhichMightUseAsyncAwaitInternally()
.then(() => "Got from network");
}
}
var result = await getFromCacheOrRemote();
Here getFromCacheOrRemote interferes correctly as type string | Promise<string> in typescript. However if an await on the function will still trigger a Promise creation and the await an eventloop iteration it won't buy anything compared to the simply solution. Seems like to profit from synchronous completions there's also some steps on the callsite needed like:
var maybePromise = getFromCacheOrRemote();
var result;
if (typeof maybePromise === 'object' && maybePromise.then != null)
result = await maybePromise;
else
result = maybePromise;
And just for clarification: I wouldn't encourage any normal application to do this kind of things, the normal async functions should be great for them. However for some libraries (e.g. high-performance networking libraries) these optimizations can make sense. And e.g. the awaitable ValueTask<T> in C# was created with exactly those scenarios in mind.
Also the consumer is not required to use await with a called async function. They can use .then on it, or pass it around to other functions that consumes promises. Or, you could pass the async function to decorators that consume promise returning functions. Using experimental decorator syntax:
Yes it is a trade off of performance for convenience and consistency.Also... the right side of await will effectively be wrapped in a simple Promise.resolve() if it is not a promise. Proof: http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap...