Flame Charting Our Way Out of Jank
Earlier last year we redesigned and rebuilt upperquad.com. While we were happy with the visual results, we knew some progress could be made on the performance front. In the initial build we prioritized the visual experience, implementing the ideal solution for what the team had envisioned. After bringing those concepts to the browser, we realized the need to make some compromises for the sake of performance.
We revisited each piece of functionality, hitting the main bottlenecks for performance. We tweaked some animations and rewrote some JS. Eventually we got to a place we were happy with and shipped it.
Roughly six months later, recently improved tools for testing and newly implemented browser APIs made for the perfect opportunity to revisit performance.
The primary tool of the performance trade is the timeline in Chrome’s DevTools. Its flame chart gives a visual representation of the JS running on a page. In short, it helps determine bottlenecks in the code. And bottlenecks distract the browser from rendering the page at a speed pleasing to the human eye, thus we get “jank” or stuttering, non-smooth movement.
Commonly performance problems are caused by repeated calls to code that is poorly written or too complex. By stepping through each piece of this code, we can pinpoint problem areas and rewrite so they perform better. In this instance, we are firing a function,
_checkHero, when the users scrolls. When they get to a certain point on the page, we hide some controls and disable the carousel functionality. However this is a pretty expensive function to call while the browser is trying to render the scrolling content.
A recently conceived JS API that browsers are just now implementing is called
requestIdleCallback. This API allows us to schedule JS functionality to run when the browser is not busy with more important tasks. For example, after clicking a button that triggers an animation, the highest priority should be showing the user a smooth animation. Additional background tasks, like firing an analytics event, can happen at some later time when the browser is idle. When applied to our
_checkHero example, we can wrap the non-immediate functionality inside the function with
requestIdleCallback. The result is drastically reducing the amount of time the browser immediately spends on the function.
Will our site performance ever be perfect? Of course not. But with progressive improvements, from learnings on other projects to taking advantage of ever-evolving browser capabilities, we can move closer and closer to that goal. The main key is to never accept your first attempt. Bust out the flame chart and dig deeper as there’s always something new to try.