I don’t think I agree. I can’t think of many tasks I’ve ever tried to solve in programming where moving the work to another thread was the right answer. Usually things are too entangled, or too fast to bother. And there’s so much overhead in threading - from thread creation and destruction, message passing with mutexes or whatever and you need to figure out how to share data in a way that doesn’t accidentally give you lower overall performance for your trouble. I’d rather spend the same time just optimising the system so it doesn’t need it’s own thread in the first place.
The mostly single threaded / async model is a hassle sometimes. But I find it much easier to reason about because I know the rest of my program has essentially paused during the current callback’s execution.
I've also found few use cases for workers in the browser, but as the parent pointed out that's partly because of the limited and sluggish communication between threads in javascript. Just to offer an opposite perspective, serverside, almost any modestly heavy processing I do with nodejs happens in worker threads. These are pooled so they don't need to spin up. Blocking node's event loop is never an option. Fine to access a big dataset with an async call, but if you need to crunch that data before passing it to the client you pretty much have to use workers. [edit] obviously assuming you're not calling some command line process, and you're trying to chew though some large rendering of data using JS.
The mostly single threaded / async model is a hassle sometimes. But I find it much easier to reason about because I know the rest of my program has essentially paused during the current callback’s execution.