-
-
Notifications
You must be signed in to change notification settings - Fork 186
fix: Form performance improvements #7658
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
Conversation
937113b to
987f139
Compare
987f139 to
b19cfaf
Compare
3960798 to
b6ec88d
Compare
|
@bastianallgeier I am having a bit of a hard time following all the different changes in this PR, so apologies if I haven't quite understood all the aspects. But if I look at the changes necessary in all the different options fields, isn't this then a breaking change for all plugin fields using the options mixin etc.? Or custom fields now would need to define an |
|
It's quite much. I can really break it down more. But I kind of also wanted to use this PR to verify that the performance gains are actually there and as big as in my tests. The fields don't have to implement the emptyValue method. It's a performance enhancement that is helping to make things faster, but not necessary for custom fields. When your custom field does not use a lot of computed props, you won't see major performance benefits anyway. The worst offenders are fields that compute heavy stuff like the options. You also have to keep in mind that this issue is only related to the Field class. Anything that's built on top of the FieldClass class, does not have those performance issues. This is where we are heading anyway. |
| public function emptyValue(): mixed | ||
| { | ||
| return []; | ||
| } |
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.
Suggestion: I do understand that we need to add emptyValue as attr to the array-notation fields, what feels a bit like a hack but probably no better way for these. Though here in the class-based fields, I don't know... doesn't come across as a super satisfying way of doing this. Also, if we look ahead to named-parameter constructors, wouldn't it be better/cleaner to define the empty value via the default value of the value property?
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.
We could only handle this with a reflection if we want to get default value of the value prop. I'm not sure if that is worth it to be honest.
|
@bastianallgeier But if a custom field uses the |
Chunks:
Description
After looking closer at this issue and @afbora research #7641 I found multiple ways how we can improve/fix this. We have to decide if we do all the steps at once, or if we want to break them down, but I'm using this PR as a big sweep first to give you the bigger picture.
Benchmark results
To not step in the dark with premature improvements, I've created a little benchmark setup for the sandbox with a new CLI command that can help us test our changes more easily.
The results of this PR are impressive. I'm benchmarking two scenarios.
Form::reset()To reset all form fields took forever before the PR because the old Field class needed to rerun all prop and computed prop methods to make sure that there's not an invalid state for one of them which depends on the value.
I'm running this 10 times in a loop.
Before
After (2 times faster)
$page->panel()->view()Creating all the props for the view needs to create two forms: one for the latest version and one for the changed version (if it exists) This makes the reset problem from above even worse because we need to reset the form when we want to reuse it for two versions and this could also add up even more if there are nested forms (structures, blocks, etc.)
Again, I'm running this 10 times in a loop.
Before
After (3,2 times faster)
This clearly shows how the problem escalates with more form setup and reset tasks.
This should have positive performance side-effects to pretty much any part of the panel.
Running benchmarks
To test the differences, you can use the Kirby CLI in the sandbox root directory. Make sure to pull the latest sandbox changes. There's a new way to set the sandbox URL with a new custom sandbox config. In the root directory, you'll find a new sandbox.config.sample.php. Rename it to sandbox.config.php and add your custom URL in there. All options in the file will be merged with the Kirby config of the sandbox. The sandbox.config.php is automatically ignored.
Once this is done, you can run
… and …
Changelog
✨ Enhancements
::fillWithEmptyValuemethod for Field and FieldClass. This is used inFields::resetto reset the value to a correct empty one. The naming is not great, but we cannot use reset, as it exists as option in the toggles field and would collide. It's at least clear enough. This will make sure that resetting a field will be as fast as possible without reevaluating props and computed props in the old rusty Field component. This is one big source for performance hits.Field::handlerExistsandField::handlerCallmethods. Those are not directly related to this PR, but simply help to remove some redundant code. We can totally do this in a separate PR.♻️ Refactored
For review team