Fix keyed list ordering issue#1231
Conversation
|
Interesting, I'll take a look at this tomorrow. Thanks for diving in! I've been working on updating the Yew example in https://github.com/krausest/js-framework-benchmark and will push a branch that we can do perf testing on |
|
Benchmarks would be ideal. I will try to write micro-benchmarks if I have time. However, I had an idea of better implementation this morning when hiking (true story xD), I'll try it now. The fix so far is pretty dumb an inefficient. |
|
@totorigolo I just spent some time reviewing the code and I believe the main issue is how eagerly we call We need a way to move a vnode without calling detach. So I think we need to add a method to vnode allowing us to get a handle on its dom node which would allow us to move it around. Thoughts? |
1a3843c to
ec0fcbc
Compare
|
@jstarry I agree that EDIT: Also, what do you think about the other changes, |
|
Reordering with both vtags and vcomp is... buggy with keyed components 😇 |
|
Yikes! We should definitely have tests to cover all the combinations. Lists can be keyed as well :) |
|
I didn't find time today to get the benchmarks setup today. Should be able to get to it tomorrow and can help out on tests if needed |
|
Here's the branch for updating yew for the JS benchmarks project: https://github.com/jstarry/js-framework-benchmark/tree/yew-update and here's a branch that uses keys (with this PR's fixes): https://github.com/jstarry/js-framework-benchmark/tree/keyed-yew |
be083c8 to
5210c7f
Compare
|
@jstarry Could you have a look? Manual testing seems to show that the diffing is correct. We definitely need unit tests, but I am too lazy to write them (and also late on a project of mine). Maybe later 😇 Performance-wise, it's ok in some situations and bad in others. This can be visualized by putting breakpoints in Firefox DevTools for insert_before and append_child. Swapping elements is bad for instance. I have ideas to improve this, but I feel that this branch is already too old and I would like to finish this before going into performance fixes. Various ideas for performance wins:
|
5210c7f to
b0dcc42
Compare
|
Good call, performance fixes are more fun when you don't have the weight of a huge PR on top. Correctness first, optimization later 👍 |
|
About the potential memory leak I mentioned, I noticed it in the benchmark "clear rows - clearing a table with 1,000 rows. 8x CPU slowdown", where Yew has terrible results.
Yew 0.7.0 doesn't seem to have this issue though. If anyone wants to confirm this and have a look 🙂 |
|
😱 |
There was a problem hiding this comment.
Good work @totorigolo!
3 main things:
-
I think we should try to avoid needing
VDiffNodePosition::AfterandVDiffNodePosition::FirstChildso that we can cut down on DOM API calls. -
We should make sure we are matching as many keyed list items as we can.
-
Keyed vlists look pretty tricky. Maybe we can remove support for them temporarily?
yew/src/virtual_dom/vnode.rs
Outdated
| pub fn reference(&self) -> Option<Node> { | ||
| match self { | ||
| VNode::VComp(vcomp) => vcomp.node_ref.get(), | ||
| VNode::VList(_) => None, |
There was a problem hiding this comment.
We are going to have to rethink this since lists can be keyed themselves. Imagine you have a list of keyed lists that need to be re-ordered 😵
There was a problem hiding this comment.
I mitigated the issue, see the last commit (16ffa90). What do you think?
There was a problem hiding this comment.
I'm not a big fan of the side effect. What if we returned the reference of the first list element here? When the list is empty, it will return the placeholder element
|
@totorigolo I noticed that |
|
@jstarry I think that it makes sense for keyed elements. However, this imposes quite a few changes to the current reconciliation algorithm: |
jstarry
left a comment
There was a problem hiding this comment.
Almost there! I think test organization is going to be really important to make sure we are handling all the edge cases. Could you try following the precedent I set in layout_tests::diff?
|
Thanks a lot @jstarry for finishing this! 🙂 |
|
Thanks a lot for driving this effort, it was great working with you on this @totorigolo! |
Fixes: #1220
I took the opportunity to document the code as I was reading it and trying to understand how it works, and to refactor some bits as well.
For the fix by itself, look for
Reform::Keep if self.key.is_some().Still a draft because I would want to investigate performance issues: keyed list feels* slower. To reproduce, just run the new example, add a lot of persons and compare the time it takes to sort the persons when it's keyed or not.
*feels: I tried to measure it using Firefox Performance tab in the Dev Tools, but I cannot find where to read the time a box takes in the JS Flame Chart view.