-
-
Notifications
You must be signed in to change notification settings - Fork 727
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft: Improve performance for selecting long date ranges #2537
base: main
Are you sure you want to change the base?
Conversation
Hi @gpbl I created a draft PR for now because I'd like to discuss with you what I found and align with you on how to implement the rest. There's a straightforward improvement we can do with these changes. But we still have the performance issue when Do you think it's worth adding this complexity to solve this issue? If yes, I can work on it and show it to you once it's ready. |
Nice work, @rodgobbi! I believe the change is indeed a step forward. However, this line is where most of the impact occurs. Specifically, it's looping from I suspect that using How could we test this behavior in Jest? The number of calls of... what? It would simplify debugging. |
PS A suggestion from ChatGPT to improve the loop:
if (newRange?.from && newRange.to) {
let newDate = newRange.from;
const totalDays = dateLib.differenceInCalendarDays(newRange.to, newDate);
for (let i = 0; i < totalDays; i++) {
newDate = dateLib.addDays(newDate, 1);
if (excludeDisabled && disabled && dateMatchModifiers(newDate, disabled, dateLib)) {
newRange.from = triggerDate;
newRange.to = undefined;
break;
}
}
} |
@gpbl Just one important detail, we cannot rely only on the visible I'll work on what I have in mind during the upcoming week and if it works, we can review it when it's ready. About
IMO testing how many times something was called doesn't provide that much value, as different devices take different amounts of time to run the same amount of iterations. |
This is true! The reason we do that is to reset the range to start from the clicked date. 🤔 We have another way to check if a day is disabled via
This could be my chance to finally add the long-awaited performance tests to DayPicker 👯 |
@gpbl Two points about it: 2 - In theory the |
@rodgobbi Cool! I was excited to add the performance tests, and I played around with Lighthouse over the weekend. I’m learning how to set up Lighthouse with GitHub correctly—sorry for the confusion with the PR. I’ve just updated it to the main branch. I still need to write the documentation for this new
For now, I’d use these performance tests as a report here on GitHub. The job runs when a PR is labeled with |
Improve for the use case when excludeDisabled && disabled is false.
@gpbl I finished the first iteration of what I had in mind, I added the I tested the "Interaction to next paint" with the
Important note, ~ 300 ms of response time is the default expected time for the component in general when using 20x slowdown (on my machine): @gpbl Let me know what you think and if you want to integrate those changes, I pushed the first iteration I worked on to showcase it, so I still need to test better, polish the code, and implement automated tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well done, @rodgobbi! I can see the performance improvements. Give me some time to review your changes. Thanks!
// function matchers needs to verified against every day in the date range, | ||
// because of that it's the least performant one and should be deferred to be the last evaluated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting... if this is the cause of the slowness, why not refactor this into a utility that works regardless of whether it's dealing with ranges or not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understood the suggestion correctly, I think this is the case with the current implementation, and the dateMatchModifiers
utils function is already the generic function that validates any specific Date
against a list of Matcher
s, regardless of the Date
coming from a date Range
.
This is easier to understand, has less complexity, and works, but hits a performance bottleneck that the rangeMatchModifiers
solves.
Having a logic that specifically handles the Range
data structure allows us to optimize for that.
The only issue is that I don't see any other possible approach when a Matcher
is of type (date: Date) => boolean
, we need to iterate all dates within the date Range
passing the dates to the Matcher
function.
What's Changed
Update the
select
function in thesrc/selection/useRange.tsx
hook to improve the performance.Type of Change
Additional Notes
Fixes #2531