Google’s Material Web Components had a performance issue and I thought I could help. The results: 90% performance improvement in big lists removal. Here’s how I did it, and how you can duplicate it in your application.
At Vonage, we are working on a unified UI library called Vivid. A core library we are using is Google’s Material Web Components library (MWC). This library enables us to enjoy best practices like Material design, accessibility and cross-browser compatibility while delivering our components fast to our organisation.
Lately I was integrating the select box in an angular application. It went well, but after replacing one specific select box, I’ve noticed a slow in response time.
The select box was part of a form that showed up in a modal window. When I closed the modal window, the UI was stuck – sometimes for around 30 seconds!
Opening the performance tab in Chrome, I’ve monitored the app and found this:
In order to verify the error is not in our application, I’ve created a simple reproduction of the error in codesandbox. In this short reproduction, I’ve just created a new select box and added 300 options to it.
The profiling scenario is simple – start profiling, click the
Clear everything button in the app, stop profiling. As simple as that.
Profiling the app in the sandbox I’ve found something interesting – removing 300 list items took around 200 milliseconds in a blank application. That’s a lot of time to just remove elements from the DOM. Figure 2 shows this performance recording – and the perliminary result that showed that the
updateItems method and its children are the prime suspects.
I’ve opened an issue in the MWC repository. I then started to investigate this farther as we needed a quick fix for our application. After I’ve fixed it internally (we are extending the MWC classes), I thought I saw a way to solve it in MWC’s source code.
Solving the Performance Issue
Digging deeper into the recording on sandbox, I saw that one function was called a lot of times:
layout function was being called by every
list-item element. Looking at the
layout‘s code, I saw that there was no real need to run this function for every
list-item, as this function just updates the layout of the list after a change.
Because we are making lots of small changes, we can just bulk them into one big change!
An old article of mine came into mind. In this article, I’ve shown how to solve a similar problem, using a
Armed with the general solution and the automated way to test it, I dove into the code. I first wrote a test that should verify my solution is working (code snippet 1).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
After writing the code, I made sure the test has failed for the right reasons – the method ran 100 times instead of the expected 1 time. Cool!
And now to the fix – I’ve created a debounce function for the layout, and used it instead of the original layout inside the
Here’s the performance result:
Completing the Pull Request
After solving the main issue, there were some small tasks that popped up. Internal automated processes (like linting) were failing and I had to cope with that.
I really enjoyed the process. Because of time differences, I worked on a fix during the day, and at around 5am had another message from the reviewer about the status. I was eagerly waiting for these messages – the whole process was positive and constructive.
I had to make some non-performance changes too. Because the debounced method is now async, I had to add a promise to the element’s
updateComplete life cycle hook. In addition, apparently there were some hidden tests on IE that we not passing (IE took much longer than chrome and the testing framework’s timeout was not enough…).
After all was well and done, my PR was complete and ready for google.
Finding my code was going to be on YouTube
But it is wasn’t over yet. The day after, I’ve got the following message from the reviewer:
How cool is that?
I hope you enjoyed this one as much as I did. If you are a new open source contributor, do not be intimidated by big projects. Sometimes, the smallest detail (like this simple debounce contribution) can make a big difference!
You can view the full PR here: https://github.com/material-components/material-components-web-components/pull/1928
Thanks to Omer Dolev from Microsoft for the kind review.