Skip to content

Reconciliation makes more moves than necessary? #212

@luwes

Description

@luwes

Discussed in #168

Originally posted by mindplay-dk April 6, 2021
I've been interested in the reconciliation algo for a while, and I'm sort of an idiot when it comes to this stuff - it's really difficult for me to understand the reconciliation code in most of the libraries I've looked at, and frankly I didn't really trust that any of them were doing it optimally.

So I set up a use-case driven test bench with a bunch of console.log statements, so I can actually try various operations on a list, and see what sort of DOM operations result from those.

Here it is, first for Sinuous - with diff.js from the map module:

https://jsfiddle.net/mindplay/gdzrmshq/

Here, I noticed that "Rotate Up" moves 3 elements, while "Rotate Down" moves 2 elements - in either case, one move should be enough, since it's just the first/last element moving to the opposite end of the range.

I understand your code is derived from udomdiff? So here's the same test-bench for udomdiff:

https://jsfiddle.net/mindplay/o4gbaqw0/

Here, "Rotate Up" takes two moves (one of them a replaceNode) which is still one too many - while "Rotate Down" does it accurately, in a single move.

As said, I am an idiot at this stuff, but I decided to try my own naive approach - I simply remove old elements, append new elements, and then take two passes: first, I move only the nodes where moving them isn't going to break the order somewhere else - and then, I take a second pass, moving all remaining nodes that aren't already in the right place.

https://jsfiddle.net/mindplay/924xfvow/

Here, "Rotate Up" and "Rotate Down" both finish in one move.

As said, this approach is totally naive, and probably isn't blazing fast, since I'm using a two passes (and lots of comparisons with next/previous siblings) but I wanted something simple enough that I could understand it myself, being (as stated) an idiot.

Apparently, I'm not a complete idiot, because it works. 😂

I expect this simple algo could be optimized as well, because for most operations (all but "Shuffle") it doesn't actually need to do anything in the second pass - there's only one difference between the first and second pass, and it's this:

image

So, basically, if that second expression is ever false during the first pass, you can return before the second pass, because it would be fully identical to the first pass.

By the way, don't ask me why these loops are backwards. I've no idea if they need to be. I was just trying stuff, and it ended up this way, and it seems to work, so I didn't question it. (Might be good for micro perf anyway.)

I haven't benchmarked or optimized this at all, just throwing it up here for discussion.

Any thoughts? 🙂

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions