Recently I've been reading and trying out different stuff regarding optimizations of the browser's layout event (not paint or composite), but exactly layout.
The test app I'm using
I've got a very simplified social media-like app, which just displays some profile information for a user and a list of wallposts (each with 2 answers, indented to the right). You can check its code at this sandbox. And I suggest to check out the app itself in the entire browser window here. Initially 1000 wallposts are rendered, clicking Show more at the bottom of the page will add another 1000 and the DOM elements count will match the count used in the tests below. You can check the step of newly rendered wallposts from fakeApi.js on line 79, but at least 2000 wallposts must be loaded to match the environment in the test. There's a comment box, which appears below the wallpost when you click ---- Reply ---- for a given post.
My goal
I want to reduce the layout/update layer tree times for a quite big DOM tree while typing in a comment box (shown only one at a time, below given wallpost), but I want to optimize without using virtualization for now.
The setup
- Machine CPU - mobile version (on a laptop) of Intel Core i7-6700HQ@2.60-3.50Ghz
- DOM elements ~ 45k
- Browser - Chrome 80.0.3987.163
- Frontend tech stack - React, Bootstrap for CSS only, pure CSS
The results measured
Performance timeline & donut chart for the typing timeframe
As you see in the performance timeline, when typing a few characters into the comment box, there's Layout (in purple below the yellow which is the keypress event) and right after that another purple block - Update Layer Tree. The times, each per single keypress:
- Layout ~ 12ms
- Update layer tree ~ 21-22ms
- Average FPS during typing - 20FPS
Things I've tried for the optimization
- React-wise, the app is already optimized with shouldComponentUpdate and React.memo (for functional components)
- Removed e.target.innerText reference in the keypress event handler and even the entire handler
- Use BEM approach for the custom CSS (in assets/Site.css), keeping selectors simple, 1-level
- Use absolute position for the comment box
- Remove some text nodes (decreased them by around 20k)
- Removed whole bootstrap CSS bundle (app wasn't looking nice, of course)
- Removed all images
- Used will-change: transform for the comment area to promote it to a separate layout layer, but still layers metrics showed that the entire DOM layer (scroll layer) is updated too, upon typing.
Simlar apps case-study
Of course, Facebook is the closest I can think of. I recorded some stats for it, at the homepage with the news feed, I scrolled down so DOM elements were enough and in the end I stopped at ~45k, like with the test app. The results from the donut chart were interesting... As you see, way less rendering was performed while typing the same count of characters, despite the same amount of DOM elements. Of course, FB's event handlers are supposedly way more complex than mine, which just append another comment if Enter key is pressed (which results in higher event handling times at FB). Also while typing in a comment box (from the first items that appeared in the news feed) FB reached 37FPS, which is also significantly better.
The question: How can I improve the layout times for keypresses, is it possible at all? Could it be that the different HTML strucure is the reason? You can see that FB contains more nested elements at places, the test app has less nesting but more individual post items are shown. Also if I need to add more details, please comment! :)