When Apple originally released the iPhone SDK in 2008, I was extremely excited about it, and immediately started working on multiple different iPhone apps. By 2009, though, I had become so uncomfortable with Apple’s stewardship of its mobile platform that I released the one game that was furthest along, and abandoned the other games and apps. In hindsight, that probably was a good idea, because at least one of the apps I was working on (temporarily) became illegal, according to Apple’s App Store guidelines.
Instead, I started looking into writing web-based games running in Safari. As part of evaluating whether it was technically possible, whether the original iPad could even run web-based games acceptably well, I wrote a simple two player tower defense game.1 Here’s the game, running on an original iPad.
I spent very little time optimizing this code, and there’s probably plenty of room to squeeze more performance out of it. Even so, the game easily runs dozens2 of independently moving sprites, has pathfinding, and displays a progress bar on every single tower, resulting in hundreds of simultaneously, independently moving pieces — all on the original iPad.
Since then, web performance has skyrocketed. If I run sunspider on my original iPad, it totals 2761 ms. According to Macworld, the iPad Air 2 runs it in 287 ms.
You can see the game for yourself here (it only runs on iPads, because I’m detecting if it’s installed on the home screen, and because I’ve hard-coded the screen size).
Getting this tower defense game to run properly on an original iPad was easer than getting the native game I released to run properly on an original iPhone. It took me two days to write the whole tower defense game, including doing some simple optimizations. It took me months to write the iPhone game, including porting it from Apple’s native APIs to OpenGL, and spending a lot of time in Apple’s profiling tools, trying to fix performance and memory problems.
To be fair, the first iPhone was quite a bit slower than the first iPad, and very memory constrained. But still, I think this is something to keep in mind when people complain about web app performance. If you don’t think that native apps were impossible to get to perform properly one or two device generations ago, then neither should web apps be impossible to get to perform properly on today’s devices.
Having said that, the people complaining about poor web app performance do have a point. Most web apps do perform poorly. I just think that blaming browsers, and concluding that web apps can’t perform well, is misdiagnosing the problem.
Why are many web apps performing so poorly?
DOM manipulations can be slow, and are difficult to optimize
One of the reasons why my tower defense game performed quite well despite not being highly optimized is that it avoids using the DOM for most of its UI. Instead, it uses the HTML canvas3 to draw pixels directly.
Importantly, though, that’s not to say that DOM-based web apps can’t be fast. In fact, I’ve written complex DOM-based web apps that achieved native-like performance (and a native-like interaction design) way back when the target platform was IE6. However, optimizing performance on these apps can be hard, because DOM manipulation can be slow if done carelessly, and browsers sometimes behave slightly differently in ways that aren’t immediately noticeable to the developer, but result in vastly different performance across different platforms when doing the same DOM manipulations.
In short, it’s absolutely possible to write web apps that use the DOM and still perform well, but, particularly for more complex user interfaces, it does require developers to spend time optimizing their code.
And, of course, you don’t have to use the DOM if something else works better for your particular app.
As an aside, this is often where people sneer and say something like «well, it’s not a real web app if it doesn’t even use the DOM», but that seems weird to me. That’s like saying «it’s not a real native app if it uses OpenGL». Drawing some — or all — of a native app’s UI without using Apple’s own frameworks is not «a scathing condemnation» of UIKit. In fact, my own native game uses OpenGL for almost everything it draws, just like the web-based game uses canvas for almost everything it draws. And just like the web-based game uses the DOM to draw stuff like buttons and the help screen, so does my native app use Apple’s UI frameworks for this aspect of the game.
Nothing about using the canvas makes a web app any less «webby.»4 All of the good things web apps bring — cross-platform compatibility, simple deployment, a high-level language, an open platform — are available to you whether or not you’re using the DOM for most of your UI. The DOM works well for some things, and canvas works well for others — that’s why there is a canvas. Pick whichever works for you.
People use a lot of needless middleware frameworks
Back when I wrote web apps that targeted IE6, I evaluated a ton of JS frameworks. I ended up not using any of them, because all of them caused huge performance problems. This is exactly where we are today with mobile web apps. Performance of a 2005-era PC running IE6 is roughly about what you’ll get out of a 2015-era mobile phone running a current version of Chrome or Safari. It was possible to create a fluid, responsive PC web app in 2005, and it’s possible to create a fluid, responsive mobile web app now, but not if you rely on megabytes of (sometimes poorly written) JS frameworks that all have to be downloaded, parsed, and executed by a mobile browser, killing loading time, execution speed, and bloating memory usage.8
Tools don’t solve problems any more, they have become the problem. There’s just too many of them and they all include an incredible amount of features that you don’t use on your site — but that users are still required to download and execute.
If at all, web devs optimize for loading speed, not execution speed
When pages were mostly static and people were using slow analog modems to dial up into the information superhighway, loading speed was all that mattered. That’s why we have a ton of good profilers to improve loading speed, and different techniques for caching and compressing data. Loading speed briefly became very relevant again when mobile phones started connecting to the Internet, and initially suffered from very slow connection speeds. To some degree, that is still the case, and people should optimize for it.
Most web developers probably don’t optimize for loading, but even fewer optimize for execution speed. With today’s fast connections and dynamic websites. execution speed often becomes a bigger issue than loading.
Admittedly, optimizing load times is easier than optimizing execution speed, since we have more experience doing it, and the profiling tools for loading optimization are more sophisticated. But it is becoming increasingly important to look at execution speed, as well.
And finally, the thing that kills mobile performance: loading dynamic, animated, interactive overlay ads from crappy, slow third-party ad servers. How often do you open a page on your mobile browser, and it’s painfully obvious that the thing you actually want to see — an article, for example — has already loaded, but is hidden below layers and layers of shitty ads that are slowly pulling in stuff, preventing you from accessing the thing you actually want to see?
You can’t have a fast web app if you’re monetizing it by punishing your users with shitty ads.
It’s frustrating to see people complain about bad web performance. They’re often right in practice, of course, but what’s annoying is that it is a completely unforced error. There’s no reason why web apps have to be slow. The technology to make fast web apps is here — we just have to take advantage of it.
I never continued work on it, because I eventually became so uncomfortable with Apple’s behavior (and Android got to a point where it was a valid alternative to iOS, and arguably even superior in some ways) that I pretty much stopped using iOS devices altogether.
If you are one of the select few good JS devs, please apply here :-)
Via Marco Arment.
If you require a short url to link to this article, please use http://ignco.de/703