Hey everyone! Since February we’ve been a bit quiet on the performance team and we wanted to share some of the things we’ve been working on and to set some expectations on what we have planned for the rest of the year.
We’ve added new tooling to gather metrics on what our current performance characteristics are (in the wild). We understand that what we see (in our development sites) and what you see does not always reflect each other. We set up some initial baseline RUM measurements to see how long some Designer interaction takes, as well as the time required to download and parse the Webflow Designer’s JavaScript payload. This has helped us isolate a few of the initial scenarios and to prioritize their improvements.
In that vein, we have made progress in a few different areas. Here are a few that I would like to share:
Site Syncing
Saving your designs is very important to get right. While many of you likely know of the large infrastructure project we undertook in 2017 to convert our codebase to React.js from Knockout, you may not know some of what that has enabled. One benefit is that we’ve been able to vastly improve how we synchronize your data to our servers. We’ve been able to
- Make it faster. Before we started the mean time DOM sync measurements was around 200ms. Today it is 25% faster at ~150ms. Additionally our 90 percentile time has improved from ~750ms to ~440ms.
- Sync less often. One of the best ways to improve computing performance is to do less work. We have had some regressions that caused us to sync sites for more often than we needed. Even when your site data did not change. Fixing these has meant that not only do we spend less time syncing, we do so far less often, too.
- Change when and how we sync. Before, when the Browser DOM was our source of truth, we would have to pause and crawl the DOM before changing to preview mode or changing pages. Now that we have our own abstracted representation we can perform that sync lazily and without blocking your interactions.
There is of course more work that we can do to make syncing faster or less costly, but many of those are dependent on other architectural changes. Fortunately, this is the natural outcome of several other projects Webflow is undertaking.
Raising the Ceiling
Our Flux infrastructure is at the core of our architectural foundation. This is the bus through which most Webflow actions flow and is how all the parts of our codebase talk to each other (think of actions like messages). When I joined the company, the fastest possible path for each action was around the ~30ms range. That meant that the best case scenario our app could run at was 30 frames per second. We improved that early on and reduced that time to under 16ms for the majority of our actions (16ms is the number needed to enable 60fps in best case conditions).
We thought we had reached the best performance we could squeeze out of our current implementation. Then, Ran Segall sent us a design of an incredibly detailed site that froze Webflow for over 850ms on each attempted scroll event. This pathological case revealed to us another optimization that restored the scrolling time to ~30ms (30fps). It also sped up node selection, which used to take over 4.5 seconds and now takes only ~200ms. In all of my years, I have never seen an improvement of that magnitude.
Current Challenges
Some of our current efforts are focused on how we can enable the entire team to write faster code (by default) and how we can decrease the noise in our performance measurements.
In the first case, we’re looking to change our tooling and guidelines. For example, we use Immutable.js quite heavily today. While we love Immutable.js for a number of reasons, we have to pay a cost at many levels to convert between it and native data types, and it also prevents other optimizations we’d like to explore, such as offloading work to WebWorkers.
In the second case, we currently experience an issue where we are over-rendering most of our UI even when nothing changes. This is wasted work, and, in some cases, doubles the size of our flamecharts. By improving this, we expect to see us closer to our 60fps goal.
We know we have a lot of work to do still, and this doesn’t begin to touch on many of the more costly and painful cases, such as adding or changing classes, or modifying Dynamic Lists or symbols. There are a couple reasons we haven’t focused on those cases specifically, yet. First, we want to get the house in-order. It’s very difficult to figure out how to optimize these while scrolling can take ~800ms. Secondly, there isn’t always a clear path forward until we address more immediate concerns. We are working hard to make the leaps we need to change those.
Our hope is that you’ll forget that Webflow has a team focused on performance. Until then, expect to see us around the forums providing periodic updates.
Cheers!
– Dustan