The traffic light turns green and you steer your Tesla around the bend, leaving the city and its jammed streets behind you. Lush green meadows reaching to the horizon surround the open road ahead of you.
You floor the gas pedal and observe how you body gets pushed into the seat. The meadows start to disappear. By the time they are reduced to a green blur you are already smiling in delight.
Your users deserve the same delight. Put a smile on their face with a fast Ember.js mobile app.
We built an Ember.js mobile app for the Trumer Triathlon in Austria. The mobile app allowed athletes and spectators to view race results on their mobile phones. It included search, different rankings and detailed results of every athlete. Here is what we learned.
Set a clear performance goal
If you want to build a fast mobile app you have to define what “fast” means. With such a goal you can constantly check where you are in terms of performance and if you are going in the right direction.
Don’t define some arbitrary numbers which you then check in the render speed tab of Ember Inspector. Pick a device from the lower end of the spectrum instead. Make sure you have this device on hand. Now use it to visit a few of your favourite websites. Embrace the pain while doing that.
At this point you are ready to settle on a number. Think about this marvellous device, think about the person holding it. How long should it take to load and display your mobile app?
We decided the mobile app should load and display the main competition in under 30 seconds on a Samsung Galaxy Gio GT-S5660 running Android 2.2.1. Once the app was already loaded rendering the biggest list of athletes should happen in under ten seconds.
Develop with realistic data
Scratch the word “develop”, this is important from the start. At every step of the process you should use realistic data. In our case we just took the data from last years event and duplicated a few entries to match the number of expected athletes.
If such data is not available fake it and make sure it’s diverse. For example if you are dealing with peoples names like we did your data during development should contain multiple examples of these cases:
- A short name like “Xi”.
- A long name like “Marvin Kreisecker”.
- An even longer name like “Johann Gottfried Graf von Tattenbach zu Eberschwang”.
Don’t make the mistake of building a mobile app that looks great with uniform data during development but breaks once it is exposed to real production data.
Do as little work as possible on the device
Our mobile app displays certain information that is not directly available from data export we get from the timekeeper. Instead of loading, aggregating and calculating this additional information on every device we let the server do the hard work.
The server periodically loads the raw data export from the timekeeper and makes a few hundred additional requests to augment the athletes data. Doing this allows the mobile app to load at most three JSON files where everything is already pre-calculated. It’s only job is displaying the data.
Since the timekeeper already exports the data as JSON we could have used that API directly from the mobile app. There would have been no need for us to develop a custom backend. But by doing it nevertheless we were able to remove a big burden from the mobile app which lead to better performance.
Improve rendering of lists
Before even starting out we knew we would get into trouble with performance when it comes to rendering lists. The triathlon featured about 400 athletes in the main category so we had to display a list of rankings with around 400 entries. This combined with the fact that Ember.js is not particular famous for rendering big lists, especially on mobile devices made us think about solutions early on.
The simplest thing you can do to improve list rendering is rendering fewer items. There are a two general ways to accomplish this:
-
Use pagination to display only
N
entries at a time. In our opinion a not so great user experience in the first place. Secondly how do we figure out whatN
is? The differences between our poor Samsung Galaxy Gio and a modern iPhone will be huge. Either we punish one type of device or we would have to figure out a dynamicN
based on device performance. -
Use something like
Ember.ListView
orember-cloaking
to only render entries that are visible. Sounds like a perfect solution, unfortunately such libraries involve scroll events which we are wary of. In combination with the new kid on the block called Glimmer and old mobile devices this would mean we would have to do a ton of manual testing to make sure this libraries really work and don’t have some weird glitches.
In the end we abandoned both ideas due to time constraints and complexity and went with a custom helper that took an array of results and concatenated it to a huge string.
Ditching bindings and Ember.js template helpers was only possible because there was only a link to the details page and it was unnecessary to update and re-render a single list entry.
While this was definitely not a beautiful solution it worked flawlessly and allowed us to render the list of 400 entries in a short time. You can read Speed Up Ember.js List Rendering By Example to learn more about this specific technique.
Remove inline SVGs
Due to convenience we used inline SVGs for all icons throughout the mobile app. A single list entry had four of them. One for each of the three disciplines swimming, biking and running. And a fourth one for the link to the details page.
With a list consisting of 400 entries this meant the DOM contained at least 1.600 additional SVG nodes. Switching to a PNG based sprite-sheet and removing the SVG icons dramatically reduced the render time further.
I’m happy to answer questions and get into more detail if you are interested. Just hit me up via Twitter or email. Thank you for your time.