fullcalendar icon indicating copy to clipboard operation
fullcalendar copied to clipboard

Multi Month Plugin Forced reflow while executing JavaScript causing laggy interactions

Open DevDotJoel opened this issue 2 years ago • 11 comments

Reduced Test Case

https://codesandbox.io/s/quizzical-chandrasekhar-8kux86?file=/src/App.js

Do you understand that if a reduced test case is not provided, we will intentionally delay triaging of your ticket?

  • [X] I understand

Which connector are you using (React/Angular/etc)?

React

Bug Description

Hello,

I'm using full-calendar 6.1.4 for the react connector.

When im using multiMonthPlugin with interactionPlugin and dayGridPlugin i get a warning on my console saying : "[Violation] 'click' handler took 220ms" "[Violation] Forced reflow while executing JavaScript took <N>ms"

It happens everytime i load the page, change dates etc

Thanks.

DevDotJoel avatar Feb 14 '23 11:02 DevDotJoel

This also happens with on some demo pages (e.g. event interaction) so I assume it is a general problem. Seems to be the same as #6741

septatrix avatar Mar 12 '23 12:03 septatrix

@DevDotJoel and @septatrix , I believe you when you say this his happening, but unfortunately I'm not able to recreate. Does this happen upon page load, or after you do some action?

Could you record everything (including dev console where this error is appearing) with a screen capture tool like https://gifcap.dev/ ?

arshaw avatar Mar 13 '23 20:03 arshaw

@acerix, a recreation from you would be great as well!

arshaw avatar Mar 13 '23 20:03 arshaw

As can be seen in the screencast it is not completely deterministic and probably depends on CPU utilization etc.

Screencast from 2023-03-14 01-03-44.webm

septatrix avatar Mar 14 '23 00:03 septatrix

Making a performance recording seems to reveal that this is due to calling getBoundingClientRect() in the PositionCache which always results in a style recalculation, i.e. forced reflow, given that any of the DOM changed compared to the last time this was called:

https://github.com/fullcalendar/fullcalendar/blob/8660e4d7327e68d15c2253d02c56a66fa1a7420e/packages/core/src/common/PositionCache.ts#L20

As it seems like this cache exists precisely to reduce this impact there does not seems to be a simple fix for this. Improving DOM structure, CSS selectors/styles etc could improve this though that is likely a rather cumbersome process. However, I noticed that the only DOM change (at least in my case) is the addition and removal of the fc-unselectable class to the body element. I am not sure which purpose it fulfills though running document.body.classList.add = console.log and thus preventing the classlist from changing prevented the violations to show up. I am sure there is a reason to set this class but just wanted to share my investigation so far and confirm my suspicion about the reflow cause.

Finally, I am not sure whether @DevDotJoel is experiencing this in the same scenario or under slightly different circumstances as they also mention page loads and date changes. In those two cases I only rarely get the warning (though the calendar I am testing with is rather empty currently), and I fear that in those cases it will be a lot harder to change anything about it (as basically the whole DOM changes in those scenarios).

septatrix avatar Mar 14 '23 00:03 septatrix

In v6.1.5 I've eliminated the fc-selectable className. The problem of reflow while clicking most likely won't be a problem anymore. Could @septatrix and @DevDotJoel please verify? If it helps, I've updated fullcalendar.io's demos page and docs examples to use the latest version

arshaw avatar Mar 21 '23 21:03 arshaw

While .fc-selectable no longer gets applied it seems that you simply set the CSS style directly which seems to still seems to invalidate the layout and leads to a forced reflow upon the subsequent getBoundingClientRect invocation. I am not sure why this is the case, maybe someone more knowledgeable in the CSS spec or the corresponding browser engines might explain what is going on here.

May I ask why the class/style gets applied and removed upon click/release? It seems like this is only the case for calendars with selectable or editable (at least by checking the different demo calendars). Would it be possible to simply apply the user-select: none style to the whole calendar upon initialization if one of those plugins is active and explicitly remove it on events which have editing disabled? This way it would not have to be set and removed all the time. Maybe someone could explain the purpose of why this is required.

Also I would like to emphasize that for me this is barely noticeable and hundreds of ms as reported by Joel. I mostly see values around 50ms. I mostly participate as it bugs me to see warnings in the dev console and problems like these can often point to underlying issues.

septatrix avatar Mar 21 '23 22:03 septatrix

While .fc-selectable no longer gets applied it seems that you simply set the CSS style directly which seems to still seems to invalidate the layout and leads to a forced reflow upon the subsequent getBoundingClientRect invocation. I am not sure why this is the case, maybe someone more knowledgeable in the CSS spec or the corresponding browser engines might explain what is going on here.

May I ask why the class/style gets applied and removed upon click/release? It seems like this is only the case for calendars with selectable or editable (at least by checking the different demo calendars). Would it be possible to simply apply the user-select: none style to the whole calendar upon initialization if one of those plugins is active and explicitly remove it on events which have editing disabled? This way it would not have to be set and removed all the time. Maybe someone could explain the purpose of why this is required.

Also I would like to emphasize that for me this is barely noticeable and hundreds of ms as reported by Joel. I mostly see values around 50ms. I mostly participate as it bugs me to see warnings in the dev console and problems like these can often point to underlying issues.

Hey, im still facing the same issue but the ms is lower. In my case im using a modal that when u choose a date it opens with input fields using states. Everytime i delete the input it lags and it shows the reflow message

DevDotJoel avatar Mar 27 '23 21:03 DevDotJoel

this problem is still ocurring in these versions: "@fullcalendar/core": "^6.1.10", "@fullcalendar/multimonth": "^6.1.10", "@fullcalendar/react": "^6.1.10",

I also noticed this happens if i only use multiMonthPlugin

is there a fix for this anytime soon?

DevDotJoel avatar Jan 16 '24 16:01 DevDotJoel

this problem is still ocurring in these versions: "@fullcalendar/core": "^6.1.10", "@fullcalendar/multimonth": "^6.1.10", "@fullcalendar/react": "^6.1.10",

I also noticed this happens if i only use multiMonthPlugin

is there a fix for this anytime soon?

i even opened the example that you guys give here : https://fullcalendar.io/docs/multimonth-stack-demo

When i open the console i saw the same warning : Forced reflow while executing JavaScript took 90ms. Just refresh the page over and over and you will see.

DevDotJoel avatar Jan 17 '24 21:01 DevDotJoel

I've found this no longer happens in the newly-released v7.0.0-beta.0. Performance for multimonth view is much better.

Updated repro: https://codepen.io/arshaw/pen/OJKMOQZ?editors=001

arshaw avatar Oct 01 '24 22:10 arshaw