← Back to context

Comment by Yokohiii

3 days ago

Maybe I am missing something. But the function coloring problem is basically the tension that async can dominate call hierarchies and the sync code in between looses it's beneficial properties to a degree. It's at least awkward to design a system that smoothly tries to blend sync that executes fast and async code that actually requires it.

Saying that fs.readSync shouldn't exist is really weird. Not all code written benefits from async nor even requires it. Running single threaded, sync programs is totally valid.

The function coloring problem represents multiple complaints. I disagree that the propagation of async makes the sync case irrelevant. In the frontend, receiving a promise has completely different implications on loading states. In the backend, I usually try to separate side-effects from pure functions, so the pure functions are usually sync.

Because JS is single threaded, fs.readSync will freeze the entire app. The only case where I would find that acceptable is in cli-scripts. But that could also be achieved with nodejs’ support for top-level await. There's perhaps a slight overhead from the Promise being created, but JS-Engines have so many optimizations that I don't even know if that matters. If nothing else is scheduled, awaiting a promise is functionally the same as blocking. Even in rare cases where you do want to block other scheduled events from running, you could achieve that with an explicit locking mechanism instead.

You could argue that filesystem access is fast so blocking everything is fine, but what if the file happens to be on a NAS somewhere?

'readSync' does two different things - tells the OS we want to read some data and then waits for the data to be ready.

In a good API design, you should exposed functions that each do one thing and can easily be composed together. The 'readSync' function doesn't meet that requirement, so it's arguably not necessary - it would be better to expose two separate functions.

This was not a big issue when computers only had a single processor or if the OS relied on cooperative multi-threading to perform I/O. But these days the OS and disk can both run in parallel to your program so the requirement to block when you read is a design wart we shouldn't have to live with.

  • > tells the OS we want to read some data and then waits for the data to be ready

    No, it tells the OS "schedule the current thread to wake up when the data read task is completed".

    Having to implement that with other OS primitives is a) complex and error-prone, and b) not atomic.

    • The application in question is frozen for that period though, that's the wait they're referring to.

      Even websites had this problem with freezing the browser in the early AJAX days, when people would do a synchronous XMLHttpRequest without understanding it.

  • he was referring to fs.readSync (node) which has also has fs.read, which is async. there is also no parallelism in node.

    i don't see it as very useful or elegant to integrate any form for parallelism or concurrency into every imaginable api. depends on context of course. but generalized, just no. if a kind of io takes a microsecond, why bother.

> Not all code written benefits from async nor even requires it. Running single threaded, sync programs is totally valid.

Maybe, but is it useful to have sync options?

You can still write single threaded programs

  • I mean single threaded + sync.

    Sync options are useful. If everything is on the net probably less so. But if you have a couple of 1ms io ops that you want to get done asap, it's better to get them done asap.

    • > But if you have a couple of 1ms io ops that you want to get done asap, it's better to get them done asap.

      and async prevents this how?

      3 replies →