This just in!
Slides available here. Hope you enjoy!
This just in!
Slides available here. Hope you enjoy!
Today I had the pleasure of opening the doors of our company to about 500 engineers at Commit Porto 2016. This presentation is mostly about problems found when developing our new Betfair mobile web application, but its principles are mostly related to big single-page applications that have client-side rendering. Take a peak now, I’ll post a video as soon as available!
Hope you enjoy it and if you have any questions just post them here or drop me a line!
Following the request of many families, here are the code snippets from my last presentation:
They are organised by page/slide but I can’t guarantee they’ll all run smoothly. Please shout if you see any problem!
Oh how I hate sticking powerful code into boring PowerPoint slides… But sometimes that is actually the most practical way of sharing a lot of code to many people at once.
I hope you enjoy it and some feedback would be much appreciated!
One of my most recent and interesting challenges was building a module where you can scroll, search and filter through a really long list of horse racing-related bets. These numbers can quickly sum up to be more than a thousand entries, meaning a lot of information must be shown in a small device with slow network speed and sparse processing power.
The first idea that comes to mind is probably pagination. It solves most network issues by making only small requests, scales really well and since you’re only processing small chunks of data each time, you probably won’t suffer from performance issues.
But when you want to scroll through all those horses and not feel like you’re using a website, pagination – even if performed automatically as you scroll down – just can’t allow you to get that responsive feeling as most native applications usually offer. Furthermore, in such a scenario all searches must be done server-side and those results also need pagination. So we aimed to be able to have 10.000 list items with the best possible experience and fast rendering in my four-year-old iPhone 4S.
A quick search on the web shows that the new trend is virtual scrolling and since we have an AngularJS app, we immediately considered angular-vs-repeat, which is quite an amazing directive that wraps your good old ng-repeat and gives it a huge performance boost by rendering only a visible subset of a potentially huge list. Unfortunately this out of the box solution couldn’t work for us since we needed some very specific fine tuning in order to save some extra requests.
So we opted for angular-inview, a simpler AngularJS directive that just informs you when an element becomes visible or hidden. This way we could easily build a custom solution, so we tried 4 different approaches:
|Loading Time MBP||Loading Time iPhone 4S||Watchers count|
|(a)||120 seconds||N/A (crashed)||42.000|
|(c)||8 seconds||100 seconds||1.200|
|(d)||5 seconds||30 seconds||1.500|
(a) First we started by measuring how much it would cost us to render a full list of 10.000 elements, each of them with a lot of code in it (directives, filters, etc.). The results were not surprising. My Macbook Pro took around 2 minutes to get everything ready and my iPhone’s Safari just crashed.
(b) Then we applied angular-inview directive to every row. If the row was in the viewport, we’d render the content. If the row was outside the viewport, we’d render a placeholder with no data. My laptop timing improved a little bit, but a quick analysis of what was happening showed that the browser was losing a ton of time on angular-inview.js in a hander that was bound to the scroll event. For every row there was a scroll handler and that’s a very, very, bad idea.
(c) So instead of attaching the in-view directive to every element, we tried bucketing the data in groups of 30 rows allowing us to have 1/30 of the handlers. The results were quite surprising: Chrome was now taking only 8 seconds to render everything and the iPhone finally started showing us our list with no problems… in 100 seconds. Having a module that takes 100 seconds to render is as good as nothing, so we still needed a better solution.
(d) It turns out the iPhone was really slow rendering lots of HTML. It wasn’t a matter of scripting anymore, but actually the fact that we were rendering almost 10.000 placeholders that contained some simple styled HTML. As soon as we understood this, we started only rendering placeholders for the buckets that were close to the viewport. The other ones would just render an empty placeholder with the appropriate size. We got some slightly better numbers for Chrome, but a major improvement for iPhone.
Is 30 seconds still a lot? Sure. Could we improve this solution even more? Probably… But if premature optimization is the root of all evil and when we test this solution with a real scenario we get a snappy application even on older devices, maybe that’s a sign we can take the rest of the day off.🙂
I’ve recently discovered that angular-touch doesn’t do a great job on link-based navigation. Although it prevents the 300ms delay that mobile browsers implement while trying to figure out if your tap on the screen was a click or a double-tap zoom gesture, it only does so for click handlers (through the use of ng-click), not anchors.
Since many Angular apps use links to navigate throughout its multiple views (and they should, SEO-wise), either we implement click handlers for all the links or live with that very annoying delay where the app is just doing nothing, when it could already be loading the next page.
With that in mind, I’ve just created a tiny project called angular-touch-faster. It is intended to be a small set of directives to give our Angular mobile apps that extra performance kick.
For now, I’ve only included an extra ‘a’ directive. It simply registers a click handler on all existent anchors, switching your browser’s location with the content of the anchor’s href attribute. Just include the module as your app dependency and you can immediately feel the difference.
Not only that, but you also don’t lose the active state on the element you clicked, giving the user some much needed feedback while the browser is navigating away.
Or even better, contribute here: https://github.com/onemanclapping/angular-touch-faster