diff --git a/.changeset/removes-and-descendants.md b/.changeset/removes-and-descendants.md new file mode 100644 index 0000000000..8162594390 --- /dev/null +++ b/.changeset/removes-and-descendants.md @@ -0,0 +1,5 @@ +--- +"rrweb": patch +--- + +Performance refactor to avoid 2 function calls (bridging between #1543 and #1652) diff --git a/packages/rrweb/src/record/mutation.ts b/packages/rrweb/src/record/mutation.ts index 08e927a98f..d56cc371c1 100644 --- a/packages/rrweb/src/record/mutation.ts +++ b/packages/rrweb/src/record/mutation.ts @@ -6,7 +6,6 @@ import { isShadowRoot, needMaskingText, maskInputValue, - Mirror, isNativeShadowDom, getInputType, toLowerCase, @@ -169,7 +168,7 @@ export default class MutationBuffer { private addedSet = new Set(); private movedSet = new Set(); private droppedSet = new Set(); - private removesSubTreeCache = new Set(); + private removesAndDescendants = new Set(); private mutationCb: observerParam['mutationCb']; private blockClass: observerParam['blockClass']; @@ -367,9 +366,11 @@ export default class MutationBuffer { } for (const n of this.movedSet) { + const movedParent = dom.parentNode(n); if ( - isParentRemoved(this.removesSubTreeCache, n, this.mirror) && - !this.movedSet.has(dom.parentNode(n)!) + movedParent && // can't be removed if it doesn't exist + this.removesAndDescendants.has(movedParent) && + !this.movedSet.has(movedParent) ) { continue; } @@ -379,7 +380,7 @@ export default class MutationBuffer { for (const n of this.addedSet) { if ( !isAncestorInSet(this.droppedSet, n) && - !isParentRemoved(this.removesSubTreeCache, n, this.mirror) + !this.removesAndDescendants.has(dom.parentNode(n)!) ) { pushAdd(n); } else if (isAncestorInSet(this.movedSet, n)) { @@ -515,7 +516,7 @@ export default class MutationBuffer { this.addedSet = new Set(); this.movedSet = new Set(); this.droppedSet = new Set(); - this.removesSubTreeCache = new Set(); + this.removesAndDescendants = new Set(); this.movedMap = {}; this.mutationCb(payload); @@ -750,7 +751,7 @@ export default class MutationBuffer { ? true : undefined, }); - processRemoves(n, this.removesSubTreeCache); + populateWithDescendants(n, this.removesAndDescendants); } this.mapRemoves.push(n); }); @@ -814,35 +815,20 @@ function deepDelete(addsSet: Set, n: Node) { dom.childNodes(n).forEach((childN) => deepDelete(addsSet, childN)); } -function processRemoves(n: Node, cache: Set) { +function populateWithDescendants(n: Node, s: Set) { const queue = [n]; while (queue.length) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const next = queue.pop()!; - if (cache.has(next)) continue; - cache.add(next); + if (s.has(next)) continue; + s.add(next); dom.childNodes(next).forEach((n) => queue.push(n)); } return; } -function isParentRemoved(removes: Set, n: Node, mirror: Mirror): boolean { - if (removes.size === 0) return false; - return _isParentRemoved(removes, n, mirror); -} - -function _isParentRemoved( - removes: Set, - n: Node, - _mirror: Mirror, -): boolean { - const node: ParentNode | null = dom.parentNode(n); - if (!node) return false; - return removes.has(node); -} - function isAncestorInSet(set: Set, n: Node): boolean { if (set.size === 0) return false; return _isAncestorInSet(set, n);