Skip to content

Optimize menu performance #329

Open
Open
@afshin

Description

@afshin

Problem

In jupyterlab/jupyterlab#9757 (comment) @krassowski writes:

Analysis:

I am currently focusing on the delay visible when moving mouse out of the menu and the over again (this is universal problem when the test > notebook is open and affects all menus, including menu bar and context menu):

slow-baseline

After lower than expected improvements in #273 and failure to eliminate this even when commenting > out handlers for mousemove, mouseenter and mouseleave I went a step further and removed event listeners from lumino's Menu for > mousemove, mouseenter and mouseleave altogether. To my surprise the issue did not go away - it was still present when looking in the > profiler; we don't see any layout shifts but a lot of long Recalculate Style tasks; those are preceded by Schedule Style Recalculation > which helps to narrow down where it is coming from.

Screenshot from 2021-12-22 22-20-39

The profiler does not show why those come to be - just that they follow browser-native HitTest (and precede the actual event emission). > The raw JSON profile file hints that the HitTest goes to the notebook cell (not unexpectedly, this is where my cursor lands after leaving > the menu) and also mentions intersection observer (IntersectionObserverController::computeIntersections) kicking in from time to time (due > to lazy notebook rendering I suppose):

The following experiment suggests that this might be triggered by HitTest when mouse leaves the menu (and then HitTest for some weird > reason causes style recalculation on Chromium/Blink):

  • on top of initial changes in lumino#273 add a <div class="test"> with > z-index=z-index of menu - 1
  • make that div position:absolute and cover entire viewport (height:100%; widht: 100%) so that it occludes the rest of the DOM (except > for the menu)
  • optionally add background: grey; opacity: 0.5 just to see the div
  • see that moving mouse out of the menu and back again does not cause the delay anymore

now-smooth

And this time there is no style recalculation anymore nor scheduling of it:

Screenshot from 2021-12-22 22-18-45

Now the behaviour of Hit test is standardized by W3C: https://www.w3.org/wiki/Hit_Testing, but it is not well understood topic when it > comes to performance optimization. There is one [question on SO](https://stackoverflow.com/questions/41830529/> optimizing-native-hit-testing-of-dom-elements-chrome) which concerns the Hit Test taking a lot of time itself, but in our case the problem > is not the presence of Hit Test but that it sometimes schedules style recalculation.

So why a Hit Test might schedule a style recalculation even though nothing changed in the DOM? Why does it not happen every time but just > some times? Well :hover pseudo selector might be the answer. We can test that by adding:

<style>.test:hover{background:red!important}</style>

This indeed restores the Schedule Style Recalculation and Recalculate Style tasks (although this time style recalculation is super fast > because only our test div is affected):

hover

Screenshot from 2021-12-22 22-17-06

While I only tested on Chromium-based browsers, I would not be surprised if other engines are affected too.

Potential solution

In a further comment, @krassowski proposes

Proposed solution

Could we add a <div> occluding background DOM when menu is open? The div would be effectively transparent (this could be implemented e.g. > with opacity: 0.01) and clicking on it would detach it from DOM and close the menu. This means that when user has a menu open and clicks > outside, e.g. on a link, it would not open (unless they click again after menu gets closed).

The UX would be consistent with how native menus (both context menus and application-level menus) work in Chrome (on Ubuntu), in GNOME and I > suspect in many other applications/environments: neither hover nor click works on background elements when menu is open. Firefox does a bit > of both: clicks do not work on background elements when context menu is open, but hover styles do; clicks do work in Firefox though when the > topbar menu is open (as do hover styles).

And it be super fast regardless if the number of nodes in the DOM is 6000 or 600000.

Edit: just in case if someone was wondering, setting pointer-events: none; on the jp-LabShell does not solve the issue.

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingperformanceAddresses performance

Type

No type

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions