The complete failure of early Java iterations of green threads and fall back to 1:1 OS threads, along with terrible async ergonomics in Java, meant a lot of backend software was based on real OS thread e.g. per connection. The story was similar in C/C++ for different reasons - the details of select and its various extensions were some of the least portable parts of otherwise POSIX interfaces. And on the lower end e.g. Python also relied on OS threads unless you built your entire application around one of the early async reactors.
The real success story behind node is libuv. It's a shame it was married to such a mediocre language, but that language did have some of the least-bad async ergonomics at the time (nearly by accident - client-side JS had to yield to the browser frequently, and the language was mostly designed to run small code blocks instead of application lifecycles).
The real success story behind node is libuv. It's a shame it was married to such a mediocre language, but that language did have some of the least-bad async ergonomics at the time (nearly by accident - client-side JS had to yield to the browser frequently, and the language was mostly designed to run small code blocks instead of application lifecycles).