[whatwg/dom] Proposal: A Range.prototype.replaceContents(...) (#837)

### Some Background

While many claims that the DOM is slow, I've been happily using it for about 20 years without any major performance issue, and in more than a challenging situation where performance matters the most.

However, most of the Web community, in the recent years, switched to this vDOM concept, unsatisfied by most common changes at once that should be reflected on the UI, and while I don't want to spam this proposal with all my libraries that never really needed a vDOM but competed pretty well anyway, I'd like to discuss the fact that I've been trying to use most common/known algorithms to produce the least amount of changes needed from UI A to become UI B.

I've tried the [Levenshtein distance](https://github.com/WebReflection/majinbuu#readme) one, to realize it was working on a way too big matrix, switching to the famous [E.Meyers's O(ND)](https://github.com/WebReflection/speedy-myers#readme) diffing, to realize that I had to bail out after "_50 snakes_" or something, because too slow when [thousand rows](https://github.com/krausest/js-framework-benchmark#readme) get replaced.

Last, but not least, I've recently discovered that a simplified version of [the Hunt Szymanski algorithm](https://en.wikipedia.org/wiki/Hunt%E2%80%93Szymanski_algorithm) works pretty damn well in every common DOM occsion, including the _replacing thousand rows_ with new content.

However, the fact all this has to weight on user-land, when there is a clear opportunity to have it native, starts becoming an issue, specially because it's super hard to compete with non standard frameworks, including mine, so that I'd like to propose this [addiction to the current Range API](https://dom.spec.whatwg.org/#dom-range-range).

# The Proposal

Among many useful methods, a `Range` instance can extract, delete, get content, but it's incapable of replacing such content _in a single operation_.

The whole Web is full of fragments able to inject even thousand nodes in a reasonable speed, and at once, but there's no mechanism to ask the _browser_ to replace many nodes with the same ease.

Sure, one could append a comment node after the last boundary of a fragment, delete the fragment content, and `insertBefore` that node, but this is more a hack than a solution, and it's also not optimizable right away, as the two operations are atomic, hence rightly independent.

This `.replaceContents(...)` method proposal would like to propose, and analyze, the feasibility, and eventual performance benefits, of defining a range boundary, and replace through an `Array` of nodes, all the range content at once, expecting some smart diffing provided behind the scene, in a world where diffing algorithm live since about ever, and are mostly Open Source.

The reason it should accept an `Array`, instead of a framework, is that we still miss [persistent frameworks](https://github.com/whatwg/dom/issues/736) on the platform, and a DOM cannot simultaneously live in two different container.

An `Array` could contain literally any node that is either live or not on the document, enabling the diffing possibilities between current UI status and the new desired one from the developer.

## Details

When `range.replaceContents(entry)` is invoked:

  * if the `entry` is a generic DOM node, handle it as if it was an array with that single `[entry]`
  * if the `entry` is an `Array`, replace all nodes in the range with those present in the `Array`
    * per each node in the `Array` that was already live on the document, avoid processing all common tasks such as notifying the `MutationObserver` of the container, or invoking `disconnectedCallback` and consecutively `connectedCallback` for an operation that was meant to never trigger any of this, as the node was supposed to never leave its container, which is what every HTML/SVG engine is trying to do these days _by hand_
  * if the entry is neither a DOM node (including fragments, of course) nor an `Array`, throw a `TypeError`

### Implementation Details

The proposal is kept simple on purpose, because usually optimizations/implementation details are not defined in specs, but my expectations is that browser engines can natively decide the best strategy to adopt in order to substitute the least amount of nodes in the document, so that behind the scene a 1000 rows replacement could result in "_just two swapped rows_" operation, and be blazing fast at that.

Regardless, the clause on how nodes that where there before should be handled is part of this proposal, because it's the most essential bit to make such proposal useful at all.

If that clause is ignored, or not implemented, nobody will use this proposal because inferior to what most modern frameworks can do already.

## Conclusion

I think having such primitive on the Web would potentially be a game changer, and I, just to name one, would switch to such API as soon as implemented.

Best Regards


-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/837

Received on Friday, 28 February 2020 20:57:55 UTC