As a JS and async/await outsider, just looking at the README example, can anybody please explain what's the reason to have the await prefix syntax at all? At this rate it's going to be all over the place. If the function is asynchronous, what's the difference for the caller? Can't it just be omitted?
If `await` could be omitted, every async call would be blocking. Sometimes you don't want that. E.g. you can store a `Promise` in a variable and then `await` it later (or even just never `await` it and let it resolve/reject and ignore the result).
Since `Promise` is a value itself, and it can be passed around, you can create combinators for them (e.g. wait for all promises in a list to settle, for any promise to settle, etc.) This can only be done in userspace of promises are a value themselves, and this requires a difference between `Promise<R>` and `R`, and a way to (blockingly) turn `Promise<R>` into `R`. That way is `await`.
If `await` could be omitted, every async call would be blocking. Sometimes you don't want that
It’s not a core detail though, you could have ‘nowait’ keyword for that, or a coroutine resume wrapper which returns a future/promise, or a coop-threading syntax like:
result = co.race [
expr1, expr2, expr3
]
The specific form is not important, and Promise is not incompatible with it, they could live together.
Promise/generator-based only cooperative multitasking is a trade-off between low-level layer complexity and userland syntax requirements. One can have first-class stackful coroutines, see e.g. Lua. The reason it’s not implemented in js is purely historical and socially-technical. It’s hard to convince browser makers to make all of their native interfaces coroutine-aware overnight.
If you omit await, the returned calue is a promise which you can keep for later, instead of waiting right now.
Say you want to kick off something you know will take a while, do some ofher things (async or not), THEN wait for the original async operation. (Or even say, wait for multiple promises to finish)
Thanks, I understand it, but my issue is that more and more libraries and functions are now asynchronous, so the await prefix is going to be everywhere. Maybe it should've been the other way around - when calling an asynchronous function you get the result by default, and can get the promise if you want (as it happens much less frequently):
const res1 = func1(); // async or not, wait for the result
const res2 = func2(); // async or not, wait for the result
let res3_p = promise func3(); // async function, but we want the promise
> Maybe it should've been the other way around - when calling an asynchronous function you get the result by default, and can get the promise if you want
I don't know why you're getting downvoted, indeed maybe it should have been the other way around. I personally would have preferred it, but there's 2 main problems:
The first is backward compatibility. If the function returns a promise in older JS implementations, it needs to continue to do so. If the promises are now magically unwrapped unless there's a `nowait`, many things would break.
The second is the single-threaded nature of JS, both Node webservers and browsers. JS execution is (usually) single-threaded, and _needs_ a lot of async calls to give the illusion that it's doing things in parallel (eg serve several HTTP requests). This illusion works well-ish because we are _forced_ to have so much asynchronicity, if it was optional it would be a huge pain for the dev to manually ensure that they are sprinking asynchronicity enough: the concurrency abstraction would leak much more than it already does.
If a function is async it's because it is potentially long-running or expensive. I don't want that fact hidden.
I don't find `await` particularly bothersome to write, and it explicitly tells me which calls are async and can be used in promise combinators or called non-blocking.
Another reason: when you `await` a promise your function pauses until promise resolution and other code will run meanwhile.
In contrast, since JavaScript is single-threaded, calling synchronous functions means only that function will be run and will immediately return to your code, with nothing else happening in-between.
The semantics are very different. Implicit `await` will quietly introduce this concurrency point, which can lead to a variety of bugs due to the unexpected order or execution.
It is okayish in TypeScript, but in js one subtle missing await also leads to unexpected everything. Mass-await in a language without types is a bad idea generally, but we have no alternatives for “the web”.
It's not a problem with types. It's a problem with call semantics.
If `foo()` behavior depends on whether `foo` is async or not, you're implicitly introducing yield points that might lead to bugs like race conditions.
Even worse: if you're calling a sync function and you (or a library author) turns it into an async function, it will silently introduce the yield point without anybody noticing.
Both sync and async `foo()` would return a `T` so TypeScript won't help with that.
You may still have race conditions with await. It doesn’t prevent anything, though I see your point if we are talking about flow control (not just net/io) via coroutines. That is race-prone in general, but most of the code is a non-leaking ‘let; await fetch(); return’ in one way or another. If someone is writing code like:
public_state = a
[await or autoawait] task()
public_state = b
and then uses/modifies that state concurrently, maybe it’s time to pull their program design out of '90s.
Both sync and async `foo()` would return a `T` so TypeScript won't help with that.
async function foo(): Promise<string> {
return "foo"
}
async function bar() {
var s:string
s = foo()
}
Type 'Promise<string>' is not assignable to type 'string'.
I meant this. In js you just get a promise into ‘s’ and then save ‘[object Promise]’ into a database.