The worst time of day to travel. For many it’s not possible to travel at any other time of day because they need to get to work by 9am.

This is exactly what a lot of web code looks like today: everything runs on a single thread, the main thread, and the traffic is bad. In fact, it’s even more extreme than that: there’s one lane from the city center to the outskirts, and quite literally everyone is on the road, even if they don’t need to be at the office by 9am. It really is one of the trends I see, and you don’t normally have to go far to find stats (look at HTTP Archive or one of Alex Russell’s many tweets) that show that there’s more code than ever on the main thread, and that it’s looking to increase over time.

There’s one lane from the city center to the outskirts, and quite literally everyone is on the road, even if they don’t need to be at the office by 9am.

It’s hard to question or change this norm. We load our JavaScript, it runs as and when it needs to, and we’ll do what we can to maybe run it async or deferred. But honestly we all have a bunch of other constraints to think about: we have Marketing saying that the masthead image for this month’s promotion is everything, we know that Business Development wants to run analytics to understand customers, Project Managers are expecting us to ship features, and people will snark tweet if stuff isn’t performant or doesn’t work across browsers.

Okay, but what can we do about it? Taking the case of the roads there are a few options, which range in effectiveness and pragmatism:

Increase capacity. Essentially make more roads. Move traffic to other roads. In the UK you can’t ride a bike on a motorway (highway if you prefer) because, well, you’d almost certainly be injured or killed due to the speed at which other traffic is going. The bikes, then, represent traffic that is only allowed to use certain types of road. Stagger the traffic. Instead of everyone traveling at 8.30am, if people were able to shift their work days and we could spread traffic out over the course of the day, then theoretically the roads ought to be, on average, quieter.

What would it look like if we applied these three concepts to the web?

Increase capacity

Year on year companies ship better phones, that is true. However, it’s also true that the lower bar has actually gone down, such that the gap between entry level and flagship devices has never been wider. In essence, then, relying on increased capacity would be similar to telling someone that they need a supercar to drive on a given road, or, in our case, ‘please upgrade your phone or computer to something “good enough”’. I personally can’t imagine telling someone to do that, especially if what they had was all they could afford, and I don’t think we should ever bank on increased resources to mask capacity issues. True of transport, true of code.

The gap between entry level and flagship devices has never been wider.

Move traffic to other roads

An important distinction we ought to make here, particularly when it comes to JavaScript, is which traffic deserves to be on the main thread. The answer is simple, but not necessarily easy: the UI. Only code that handles the UI deserves to run on the main thread. This is the thread that has to account for user interactions through JavaScript, and where tasks like style calculations, layout, and paint occur. Other work, like diffing virtual copies of the DOM, analytics, fetching resources, or other business logic has little-to-no place on the main thread.

We actually have the option to move non-UI traffic off the main thread today using Workers. React & Preact use virtualized copies of the DOM that don’t technically need to interact directly with the real DOM until late in the update cycle, so this is something that we should look into more.

There are very few notable cases of people making good use of Workers, which is a shame. (I always think of Nolan Lawson’s Pokedex app, which did this awesomely!) True enough, it can be painful to navigate postMessage with Workers, and without doubt most of the abstractions many of us rely on day-to-day are not built with Workers in mind, but if we accept the premise that the main thread is often in a ‘traffic jam’, then by extension we need to seek ways to alleviate the traffic. The Worker is our primitive for doing that.

Stagger traffic

Unlike the real world, where people work collaboratively in businesses and need to be get to work by 9am (generally speaking), there is rarely a case where code must do the same.

If we have moved as much code to a Worker as possible, though, we are still left with some necessary UI-centric JavaScript that interacts with the DOM, and must therefore run on the main thread. Here there are several signals one could use to decide if a given component needs to update urgently, a good one being “it’s on the screen right now”. If it isn’t on screen, delaying its update until there’s idle time is a reasonable way to orchestrate the update.

Tick tock, tick tock. Perhaps we need a scheduler? Photo by Jon Tyson on Unsplash.

Recently Philip Walton wrote a must-read article on a strategy he called Idle-Until-Urgent, which treats UI work as non-essential by default and only upgrades render priority when certain criteria are met. As I mentioned above, my own personal preference is “it’s on the screen right now”, but even within that single criterion some components are likely to be more important than others; most likely the ones with which the user is interacting. If, for example, they want to compose an email, that’s the most important component bar none.

What does this all point to? For me, I think we need a yet-to-exist scheduler on the web platform itself. Whether you use requestAnimationFrame, setTimeout, setInterval, or requestIdleCallback, you will eventually hit the case where you create something scheduler-like, attempting to orchestrate a queue of discrete tasks. Or you won’t and you’ll run a single, long-running task that just updates everything in one go. And why wouldn’t you? It’s the default we have today. Just like driving on the roads at rush hour.

We need better defaults. We need more organized traffic.