Like I said upthread, I used to dunk on JavaScript a lot, but it doesn't make sense nearly as much as it used to, to me.
>Single-threaded isn't a benefit
Huh? Of course it has some benefits. Unfortunately everything is just trade-offs. A benefit of single-threadedness is that you don't deal with the certain pitfalls of multi-threadedness.Use JavaScript.
We can say 'til we're blue in the face that that doesn't matter (and I do, as a Ruby/Grape guy for APIs), that matters. Lowered impedance mismatch is a thing. I use Ruby because I'm still more productive there--but that's a library problem (RDBMSes), not a language problem.
Node really is good-enough. I'd go for either a JVM or a BEAM-based solution if I was building things where there were significant and meaningful losses on the table if I fucked up, but for most things? Nah. Just...not important enough.
We aren't going to agree here, but you sounded like you thought your position was axiomatic or something, and that's what I disagree with. Meanwhile I am content that we may have different preferences, that's not a problem.
Can you describe a race condition that cannot be replicated on a single thread with either preemptive or cooperative multitasking/coroutines? I'm racking my brain and can't come up with one. If your coroutines are deterministically given time, then I guess you can avoid race conditions, but "are my coroutines deterministic" seems like a really difficult thing to conclusively prove in all cases (like, just add network I/O latency), and the conceptual barrier remains the same whether they're deterministic or not.
(Edit: a friend just noted the possibility of writing to memory/disk and reading halfway through, and if you don't have atomic writes that's true, but you can have preemptive, single-process multitasking that interrupts mid-write; that's why we have file system lockfiles, isn't it?)
I use node-async-locks when writing JavaScript sometimes if I have to deal with shared state, because, hey, I might have to await something and come back to this later. (Obviously I try not to, because duh, but sometimes you're stuck with it and can't immutable-all-the-things. So you define a critical section and do your thing.)
Learn Elixir or Erlang and show that there's an alternative to Node.js that's both fun and powerful - and battle tested.
Instead, you'd rather the language be written with conscious land mines in it?
Like, I have a history of dunking on JavaScript. (Though, to be fair: ES6+ is better! It's a lot better. I kinda like it.) But C is unsafe as hell. The list of people who should be writing C is super short.
If you're running into memory links in Node, that points to bad native code or handles that are never getting removed. That's not something easier in C, unless you also like buying yourself double frees that you have to worry about. And backpressure is an architectural problem--it doesn't go away in another language, the ephemera of it just makes the problem surface in a different way.
Maybe what you're writing isn't appropriate for Node. Much of what I write isn't--if I start seeing buffers, I start reaching for another ecosystem, usually the JVM. But that's a far cry from a meaningful criticism of Node for what it's good at. Use what's good where it makes sense. Use other things where they make sense. Revisionism to have C make sense, in 2017, when we have modern, clean C++ and Rust both and Go if you really don't actually care about type systems, makes me really skeptical.
We have a handful of stupid simple http servers. We use express, redis, aws-sdk, pino, misc. Responses are mostly JSON.
The http-request module has given us the most fits. I question that any one has ever used it for more than toy problems.
The redis module is also an engineering marvel. I gave up trying to add a rate throttling shim. The goal is to limit the number of concurrent requests. Because when our app is under load, we're not processing redis responses fast enough, so redis server's outbound client buffers grow and will eventually OOM ABEND the server. So I wrote our own stupid simple redis thing using async.queue as a poor mans thread (task) pool. Trivial. Eg my REPL parser is 1/3rd the size of node-redis-parser. Works great. I keep thinking I must be missing something.
From my reading, hapi (successor to express) does an inbound backpressure thing. I'll be trying that out asap.
Much as I hate Spring, AOP, jedis, annotations, jaxrs, log4j... I've never had these kinds of nuts & bolts problems. Now I kinda miss the elephant gun approach.
PS- I can only assume the on drain event strategy was someone's idea of a practical joke. Maybe its a uvlib thing.
JS is the only language on the browser after Java and Flash were killed off.
Brendan Eich created JS.
Brendan Eich runs Mozilla.
No new browser language occurs unless the big players (including Mozilla support it)
Mozilla have killed all attempts to add new languages to the browser.
Q.E.D. - language monoculture due to one creator forcing his creation on everyone and denying anyone the chance of doing things differently.
At least Web Assembly offers some hope for a sane future where we can actually choose the right tool for the job rather than the only tool for the job.
Ran. Very briefly.
The worst aspect of nodejs is code construction (craftsmanship).
Whereas Bill Joy said of Java "Allows you to think both In The Big and In the Small, at the same time." With nodejs, not only is there no Right Way, there's not even a Good Way. You have to mind all the details, plus quite of a few new ones.
Frankly, I'd rather just write 'C' again. If I have to care about the fiddly bits, I'd rather the language not fight back.
My team spends a lot of time mitigating memory leaks and back pressure (bufferbloat due to thread/task starvation). I haven't done this kind of troubleshooting since my 'C' slinging days.
And this is apparently acceptable.
I find the current state of affairs (emperor has no clothes) appalling and baffling.