3 ms·
> when you want to do async in node, you don't have to worry that some library you are using is going to lock up your thread. > In any other language, you have
by epidemian 10y ago
> when you want to do async in node, you don't have to worry that some library you are using is going to lock up your thread.
> In any other language, you have to painstaikingly make sure everything you use isn't doing sync
I haven't found that to be the case TBH. In most other languages i've used i don't have to worry about foo() being syncronous or not. I can assume that. In other words, after the control returns from the foo() call, i can assume that what foo() is supposed to do has been completed. In the case that foo() needs to do some IO operation, i can usually rely on it doing a syscall that will block the thread and put it to sleep, instead of doing something nefarious like busy waiting.
And that's it. The current thread will sleep while the IO operation in foo() completes, and the OS (or VM if we're talking green threads) will switch the CPU to do something else in the main time. And if it's a web server we're talking about, that something else may be another web server thread, serving a different request. Yay, preemptive multitasking!
In the case of node, you do very much have to worry about a function call being synchronous or asynchronous, as it defines the way it has to be called. In the former case, it can be called "normally":
let a = foo()
// use `a`
In the async case, some code gymnastics need to be involved:
// Either callbacks:
foo(a => {
// use `a`
})
// Or promises:
foo().then(a => {
// use `a`
})
// Or promises + await syntax:
let a = await foo()
It may not seem a big problem at first, especially if using the `await` syntax is an option. But to me the biggest problem of this technique is that the "async-ness" of a function cannot be abstracted away. If a function `foo` that has always been synchronous, and that is used in several places, needs to be changed, and this change implies `foo` calling an async function `bar`, then `foo` will need to become async too, and all the places where `foo` is called will need to be changed. Even though this internal `bar` async call was an implementation detail of `foo` that shouldn't have concerned `foo` callers. And this propagates all the way up: if any of the places where `foo` was called was, in turn, a synchronous function too, then that function will also need to be refactored into an async one, and so on and so forth.
And that's basically why i find node's distinction between sync and async functions so frustrating :(
PS: Cooperative multitasking does not imply this weird syntax complexity of having two different kinds of function calls that cannot be freely intermixed. For instance, Eralng "processes" use cooperative multitasking, but the "yields" are managed implicitly by the VM, so you don't need to explicitly yield control of the current thread to let other stuff run concurrently.