At Civico, we’ve been having all kinds of issues with the commonly available video players, and as a video streaming company, that’s really bad news. These experiences, plus some future requirements that none of the standard players support, means I had to write our own video player. This meant JavaScript – lots and lots of JavaScript.


Step 1: Modules, classes, packaging and other fun

JavaScript is a mess. You have your standards (ES5, ES6 et al.) but browers either don’t support them, only partially support them (and different parts, depending on browser and/or different versions of the browser), or support them but with their own special interpretation. As a result, it seems that the “JavaScript way” is to write everything in a slightly different way than the browser uses (e.g. TypeScript, or latest ECMAScript standards) and then transpile them in to browser-compatible JavaScript, loading in a bunch of polyfills to paper over the cracks in browser support.

In my case, I have a requirement to support some very old browsers as much as possible (Internet Explorer on Windows 7, for example). For some things, this support simply isn’t possible – the browser has literally no support for the feature I need, it can’t be polyfilled in, and the developers have no plans to add the feature. Despite this, somehow it’s always our fault that it doesn’t work (here’s a nickel, kid, get yourself a better computer). To begin with, however, I’m just working on an up-to-date version of Google Chrome, and then compatibility testing with other up-to-date browsers – I’ll chase the long-tail later.

Having finished bashing JavaScript, I was happy to see that its approach to OOP has improved – you can now declare classes rather than just decorate plain objects with functions (even if it’s just syntatic sugar, I don’t really care – it makes the code easier to read and understand.) It only took me a short while to find out how to bind() a object method call where a plain function was required, and things looked good.

I was also happy to see that you can now import modules from within the JavaScript code, rather than having to either add a load of <script> tags to your document head (or tail) either statically or dynamically. This also makes structured development much more sane, as it makes dependency tracking not just possible, but actually quite easy.

I briefly bounced off using Webpack to bundle all of my JavaScript, but it soon got weird and never worked for me, and as this was bleeding-edge development it didn’t seem worth the time trying to untangle it. Maybe once the code is more mature and less volatile I’ll have time to revisit it.

Memory leaks. So many memory leaks

JavaScript is a garbage-collected language. You just leave stuff lying around and sooner or later the magick memory fairies will clean it up for you.

Unless they don’t. And they weren’t. And given that I’m working with digitial video streams here, this unreclaimed memory can build up quite significantly and quite quickly. And given that people may be watching the streams for several hours without refreshing the page, that’s bad news.

I’ve been spending some quality time with Google Chrome’s developer tools, particularly one tabs regarding memory and performance. Coming from a C/C++/other native background, I’m used to managing memory myself, so the thought that JavaScript could save me having to worry about that was nice, and I naively thought that it would all be nice and flat.

I was wrong.

It seemed that somehow, all of the fetch()s I was doing were somehow immune to garbage collection, and so my browser tab was using an increasingly large amount of memory. I was using the Fetch API because that seemed to be the new and modern way of doing things (I was going to deal with the lack of support in IE later). In the end, I re-wrote them to use the good old XMLHttpRequest, and my memory leaks disappeared (and I got IE support back). I’ve still got a couple of fetch()s to rewrite, but now I’m only leaking a couple of kilobytes per minue, rather than megabytes per second.

I’m also rather curious to see how other sites (both at work, and in general) are for memory leaks – it’s well known that A Certain Webmail Provider has an online client that can be quite grabby when it comes to RAM, and also A Certain Messaging Platform is well known for it’s poor performance and RAM requirements. Am I just being overly sensitive here? Is it really an accepted industry practice to say, “Well, they can just refresh the page to solve the problem”?

The takeaway

I can’t say I’m now a big fan of JavaScript, but I appreciate its utility, and it does have certain things going on for it. IMHO it makes some things more difficult than they need to be, and it’s not helped by the prolifigation of different browsers and versions of browsers. I am in no way saying we should go back to the old days of “Best viewed with {browser}”, but polyfills seem to be a way of avoiding the problem rather than fixing it (getting people to upgrade – and there are plenty of reasons why keeping your web browser up-to-date is a good idea). This is certainly not helped by “corporate” IT departments who are unwilling (or unable – not everyone has the resources) to do this – they have no incentive to upgrade while things still work, and we as developers are tying ourselves into knots trying to support these outdate systems.

The PHP ecosystem has taken a bold approach to this – newer versions of systems like WordPress and Laravel enforce a minimum PHP version, thus obligating hosting companies to upgrade their systems. Not only does this reduce the size of codebases (no need to have compatability code for older PHP versions, and you can use the latest language features without fear) but it also reduces developer stress – a line has been drawn, and if a hosting company is the wrong side of that line, they’re told, “Tough. Upgrade, or maintain your own patchbase to make it work – we’re moving forwards, not looking back.” There seems to have been surprisingly little pushback on this – maybe we can see the same in the browser world.