Skip to content
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

[optimization] child node reordering #8

Closed
yoshuawuyts opened this issue Aug 8, 2016 · 22 comments
Closed

[optimization] child node reordering #8

yoshuawuyts opened this issue Aug 8, 2016 · 22 comments

Comments

@yoshuawuyts
Copy link
Member

yoshuawuyts commented Aug 8, 2016

So @developit pointed out another optimization we could do is check node reordering. Often times lists get updated; items get appended or removed. Given that lists, forms and links are the staple elements of HTML this is probably worth optimizing for.

The new node comparison algorithm would then become:

  1. check if node is same, if yes do nothing
  2. compare the full array of child elements with equality checks, apply the re-order algorithm
  3. insert new children where reordering didn’t apply

I reckon this should speed up the reordering case by quite a bunch. Help welcome! ✨

@kristoferjoseph
Copy link
Collaborator

It seems like adding an ID check could also be a cheap optimization.

@developit
Copy link

That's what keys do in react, some prior art.

@reminyborg
Copy link
Contributor

reminyborg commented Jan 19, 2017

Is there a way we can do children node reordering without having to force the user to supply a identifying key for every element?
So far every implementation I have seen has had this.

Problem is when the children look alike but children's-children contains the changing content. Apart from creating a Merkle tree or having the user supply a key I cannot see any other way of doing it.
Edit: I just saw the merkle tree idea was mentioned in issue #1 🤣

I would love to help with this. ✨

@yoshuawuyts
Copy link
Member Author

@reminyborg well, each DOM element is just an object. If we set a property on the object we could use it as a unique identifier for the child nodes; removing the need for stuff to happen in userland. I think at least; hmmmm

@reminyborg
Copy link
Contributor

reminyborg commented Jan 20, 2017

@yoshuawuyts i might be wrong, in the cases of reordering with only the children's-children changing we might still end up mutating the elements instead of moving them. The effects are probably most apparent when dealing with focus.

A possible solution would be a optional "key" property. It would simplify reordering and keeping DOM state like focus intact. And if "key" is not used we can solve it optimistically.
I remember being discussed in mithril: http://mithril.js.org/mithril.html#dealing-with-focus

EDIT: I prefer morphdom's solution: Adding an ID id check on the elements as @kristoferjoseph suggested, requiring that works great for the edge cases where we want to keep a sub tree's DOM state intact (focus, input values, etc.) when reordering. Should also be suggested for optimising complex lists.

Its not apparent from morphdoms docs. We should add this to the readme when the feature ready.

@kristoferjoseph
Copy link
Collaborator

kristoferjoseph commented Jan 20, 2017

+1 on ID check
Also Merkle rees is such and interesting idea we should def add an experimental branch that tries this out.

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Jan 20, 2017 via email

@yoshuawuyts
Copy link
Member Author

I was thinking about what to name this prop, and key seems like it's the most used:

  • react has <div key=${number}></div>
  • vue has <div key=${number}></div>
  • inferno has <div key=${number}></div>

Also from infernojs/inferno#406:

Unlike React, Inferno promotes correct usage of instances where you might want, and not want, keys. Using either in different situations can have different performance characteristics depending on what is being "patched". Inferno could warn for not using keys on lists that contain stateful DOM elements that can have big issues if not keyed (e.g. inputs, selects, iframes, video, audio etc) – but that's not in scope for now. It might be a good task to add to the issue backlog though.

This made me realize that if we want to prevent onload / unonload from going haywire in lists we need to implement reordering for sure.

@yoshuawuyts
Copy link
Member Author

blep, ok I think we might need to rename it to <div data-key=${number}></div>; was just thinking about it and figured using the data- prefix might actually be a bit nicer (:

@reminyborg
Copy link
Contributor

reminyborg commented Jan 23, 2017

I was experimenting with the thought that using the element ID would be enough.

I was reading morphdoms reasonings about it in patrick-steele-idem/morphdom#3

It would require users to create document unique ID's when needing list performance or preserving DOM state. But it would also ensure that the 'children' could survive being moved to another place in the tree.

@yoshuawuyts
Copy link
Member Author

@reminyborg ah this explains a lot - I've run into issues before where I set an id on an element and it would stop updating. Didn't know why, just considered it a morphdom gotcha.

I'm not necessarily a fan of using IDs as keys, because IDs meant to be unique per page which means there could be conflicts. Using a data- attributed on the other hand feels less intrusive imo and only serves as a hint to the algorithm on how top optimize stuff

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Mar 3, 2017

actually IDs might make sense - if we document it well tho ✨ - less new words to invent

@sethvincent
Copy link
Contributor

I've found in working on an infinite list module (https://github.com/editdata/infinite-elements) that having an id or key for reordering is essential for making it work.

Using the id by default and providing the option of using an alternate key attribute might be good. morphdom has a getNodeKey option to accomplish this.

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented Mar 12, 2017 via email

@yoshuawuyts
Copy link
Member Author

From IRC:

17:04 <yoshuawuyts> how about: look over list of elements, reference each child by an id in an object, reference new children by id in object, morph nodes with same id, then loop over nodes and skip the ones that have already been morphed (e.g. do the reordering part)
17:05 <julian> yeah that sounds good, but doesn't solve the on-load problem, right?
17:06 <yoshuawuyts> it would because we never remove them from the dom
17:06 <julian> how do you reorder AB to BA without removing a node?
17:06 <yoshuawuyts> oh fuck lol
17:07 <julian> maybe on-load needs to be changed to allow this
17:07 <julian> yes i think so
17:07 <julian> it should after deletion check if "the same element" doesn't exist after all, maybe like that?
17:08 <yoshuawuyts> dang, reordering lists is tricky. appending / prepending nodes is the easier case
17:08 <julian> yeah definitely
17:09 <julian> deleting and adding in between works too
17:09 <julian> just reordering
17:09 <yoshuawuyts> luckily onload is a different concern - if we solve the algo in nanomorph then we can figure out how to best do stuff with onload on top of that
17:09 <julian> ok, cool!
17:09 <yoshuawuyts> I think at least haha
17:09 <julian> it "has to be that way"
17:09 <julian> not much we can do in nanomorph otherwise
17:10 <yoshuawuyts> yeahh
17:10 <julian> on-load should work with the concept of moving elements around
17:10 <julian> that should be a basic premise
17:10 <yoshuawuyts> we could so something like: listen for onload events -> nextTick -> check if currently in DOM -> if not in DOM fire the onunload handler
17:11 <yoshuawuyts> which would allow for detaching -> immediately reattaching DOM nodes
17:11 <julian> yeah i was thinking the same
17:11 <yoshuawuyts> woot!

@yoshuawuyts
Copy link
Member Author

Patch to fix this was merged, but current master shows a regression in certain cases:

screen shot 2017-05-10 at 11 27 16

This was from my CSSconf talk slides, when upgrading to new nanomorph things failed. Oooops.

https://github.com/yoshuawuyts/css-conf-talk/tree/master

@bcomnes
Copy link
Contributor

bcomnes commented May 18, 2017

Wondering how this could affect reordered components that return a proxy.

@yoshuawuyts
Copy link
Member Author

yoshuawuyts commented May 18, 2017 via email

@bcomnes
Copy link
Contributor

bcomnes commented May 18, 2017

Fantastic. I suspected so.

@yoshuawuyts
Copy link
Member Author

choojs/nanohtml#74 fixed the regression I encountered - haven't been able to reproduce. We should stay on the lookout for possible regressions tho

@yoshuawuyts
Copy link
Member Author

v5.0.0

@yoshuawuyts
Copy link
Member Author

This is going to be shipped in choo v6, requires #71 to land

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants