> I think you maybe haven't looked on the language with fresh eyes for a while
I'm working on a very old node codebase - it's over 3 years old, which is absolutely ancient in terms of node and the pace of its development.
And you're correct, we're not using classes, promises, or async/await. However, this being a large system that's in production, we don't exactly have time to rewrite everything to take advantage of new features, and introducing another way to do something when we already have 5 ways of doing the same thing that are different with nuances seems silly.
And refactoring a dynamic language is just orders of magnitude harder than refactoring a static language. With a compiler, you have reasonable confidence that you've found every use of a particular function or field. With dynamic languages, you're never quite sure, especially with Javascript.
That's why I said that for a long-running production system, I would advise against Node. I'm sure something else would come down the pipe that would fix your particular complaint, but might introduce one of its own. And once you already have a large mass of code, you're sort of stuck with that version unless you have time to do a complete rewrite with the new coding paradigms that might introduce bugs. Heck, we tried to just use the latest version of Node, and all of our tests passed. When we tried to deploy it to production, we had to hastily roll back because it started sigseving after a while under load.
One of the largest advantages that people tout for node is that it's easy to write large quantities of code for. But that's also a curse for stuff you have to maintain, as it almost seems like you're taking a snapshot of the Node ecosystem at the time that you start writing the program, and it's extremely hard to update/upgrade it. Hence my dislike of it for any sort of long-lived production system.
EDIT: for an example for half baked node libraries, let's take a look at handling command line arguments. The two leading contenders are minimist and commander. Minimist gives you very few features, as befits its name. Fine. But if you want anything with more feature, you get to use commander. Commander doesn't really handle required arguments properly, always uses -h as a flag to trigger help (not configurable), and when you pass in two strings as flags to set the value of a named variable, it always sets the value of the one that's listed last. (e.g, if you want -version and -ver to indicate the same flag, the library parses what you pass into it but only sets the -ver variable when it parses things). And this is the second most used command line parsing library in node, as far as I can tell.