26 comments

[ 3.9 ms ] story [ 71.3 ms ] thread
A lot of this article is background—it only really starts talking about class static blocks two thirds of the way through! If you’re familiar with the situation up to class fields (the last part of which, private class fields, has only landed in Firefox and Safari in the last few months), then you can skip to that point, the “Class static blocks” heading.

If you’re familiar with ES6 classes but not class fields, then you can skip the first half of the article and start at the “Public class fields” heading.

As someone whose programmed predominantly in Java and Python and worked on back-end type stuff, Javascript is super weird to me. I run a webservice that I noticed occasionally freezes up and crashes and had trouble figuring out why. Just the other day I realized that it was because we were DDoS'ing ourselves through a badly implemented progress-bar functionality that made use of the setInterval function in Js
Is there something particular with JS that makes this extra likely to happen compared to other languages? Or does JS simply have more developers overall, then also more beginner developers who do mistakes like this?
Async code is just hard, and most useful javascript is doing async stuff.

The code in the above comment probably should have used a recursive setTimeout() that waited for each API call to finish, rather than a setInterval().

It has more gotchas than most languages since bad backend languages just stop getting adopted, and being client-side, issues are less obvious as long as it appears to work. n^2 code that should be n with some memoization might blow up a backend service, but freezing the UI for 50 ms is ok-ish in the browser.
Blowing up the backend and a 50ms freeze is comparing apples with oranges.

If you have code that freezes the backend for 50ms you're unlikely to notice it. And if the code running in the browser blows up you're going to notice just like in the backend case.

Also, JS is not the only language that runs in the browser. You have TypeScript, as well as any language that compiles to wasm. If you want one that's not bad, it's up to you to pick one.

TypeScript doesn't run in the browser.
(comment deleted)
And WASM isn't meant to replace JavaScript. Last time I checked, its use was discouraged for general-purpose web development. It's meant to be invoked in JavaScript, not the one tool used when writing an entire web app.

If you want to write code that runs in a browser, JavaScript really is your only option.

> It has more gotchas than most languages

Where do you get this from? Has there been any comparisons made between JS and other languages to see which ones have the most gotchas? I'd love to see the data behind this.

> since bad backend languages just stop getting adopted

What? This is obviously not true (bypassing the discussion around what "bad" means, which is highly subjective). People continue to adopt all kinds of languages all the time. New projects in PHP are still created (although I disagree PHP is necessarily a bad language [today])

> issues are less obvious as long as it appears to work

Hmm, isn't it the opposite? Frontends is what the users see, when something is wrong it's very easy to see that something is broken. And if the backend breaks the wrong way, the frontend usually breaks as a result too if the programmers haven't setup error handling correctly.

> freezing the UI for 50 ms is ok-ish in the browser

Freezing the browser UI for 50ms is as noticeable as adding additional 50ms to the processing time of all backend requests. If you're actively building it you might notice that the timings off, but if you're just using it, everything might look fine. Not sure what backend/frontend makes a difference here...

The big strength and at the same time big weakness of nodejs is the asynchronous event loop.

If we ignore the cluster setup to get parallelism, concurrency in nodejs is done by running all request in the same thread by segmenting them and each sub part of a request into asynchronous callbacks.

By doing like this nodejs can achieve high performance because it avoids high cost of thread context switching.

The drawback is that one request can block all other request if some code is badly written, if only one callback takes too much time everyone needs to wait until it is finished, remember only one thread, no parallelism.

If you compare to PHP where the web server handles all process management (threads or processes), one badly implemented endpoint will most likely not affect other request to other endpoints. (Of course we have same limitations as always being on the same machine, limits on memory, cpu etc). Other endpoints will continue to work as before even if your team committed a few lines of shitty code whereas in nodejs it can bring down the entire system.

Avoiding this blocking effect in nodejs is usually not a problem if you are a skilled developer, however if not it is highly likely that you will deploy this behavior to production.

That is also in a sense a paradox of nodejs, it is pitched as something easy to pickup if you already know JavaScript, it is true that it is similar to browser JS, which is also asynchronous in a single thread, but in nodejs you run all users in one thread whereas in browser JavaScript you get a thread per user (each browser instance). nodejs may look easy, because it is just JavaScript, but it has these subtle parts that you need to be aware of even as a beginner.

For future reference it's very rare that setInterval is what you want to use (vs recursive setTimeout, like another reply suggested)

Unfortunately JavaScript is one of those languages that has lots of "never or rarely use this" cases

Why is recursive setTimeout better?
Not necessarily better.

Usually you want a recurring task that start after the previous invocation finished. Recursive setTimeout is the straight forward choice, while setInterval may require you to cancel the interval, making you just reimplementing setTimeout.

Scheduling task in setInterval will run the task every interval time set regardless the previous task has finihsed or not. This in turn will starve your hardware if the function could not finish before the next execution begin.

> Scheduling task in setInterval will run the task every interval time set regardless the previous task has finished or not. This in turn will starve your hardware if the function could not finish before the next execution begin.

That only applies to async work performed inside the callback. Once the CPU is starved, or if the work performed inside the callback takes longer than the interval, then setInterval will start to skip.

It sounds like your issue was polling and not JS. scheduleWithFixedDelay would have hurt you just as bad.
It's not the first time I complain about these articles from the same company popping up onto the front page, and I am really wondering how they are consistently doing this.

For a format that is easier to consume and isn't marketing content, see:

https://github.com/getify/You-Dont-Know-JS

> I am really wondering how they are consistently doing this.

Because they're useful articles?

As for what you linked, the second edition book about classes isn't even started, and the first edition book only goes up to ES6. If I'm here for the thing in the title, class static blocks, that doesn't help at all.

Class static blocks are weird. Give me async constructors already!
Why would you need that?
Can you not just define an async static function that returns an instance?
I can, but that's ugly - it violates standard semantics and generally introduces a new thing to know about.
You can simply return promise from constructor \m/
(comment deleted)
> It is important to note that classes in JavaScript still use the prototypal inheritance pattern under the hood. They simply provide syntactic sugar for the prototypal inheritance pattern.

With #private variables, this is unfortunately no longer true. You can’t do private variables as outlined in the spec with prototype inheritance. It’s a feature that would be very difficult indeed to polyfill.