Skip to content

Commit f41bf19

Browse files
committed
perf(snapshot): avoid recreate element a everytime
1 parent 8aaca89 commit f41bf19

File tree

2 files changed

+31
-10
lines changed

2 files changed

+31
-10
lines changed

.changeset/hungry-dodos-taste.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'rrweb-snapshot': patch
3+
---
4+
5+
Avoid recreating the same element every time, instead, we cache and we just update the element.
6+
7+
Before: 779k ops/s
8+
After: 860k ops/s
9+
10+
Benchmark: https://jsbench.me/ktlqztuf95/1

packages/rrweb-snapshot/src/snapshot.ts

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,23 +194,34 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
194194
return output.join(', ');
195195
}
196196

197+
const cachedDocument = new WeakMap<Document, HTMLAnchorElement>();
198+
197199
export function absoluteToDoc(doc: Document, attributeValue: string): string {
198200
if (!attributeValue || attributeValue.trim() === '') {
199201
return attributeValue;
200202
}
201-
const a: HTMLAnchorElement = doc.createElement('a');
202-
a.href = attributeValue;
203-
return a.href;
203+
204+
return getHref(doc, attributeValue);
204205
}
205206

206207
function isSVGElement(el: Element): boolean {
207208
return Boolean(el.tagName === 'svg' || (el as SVGElement).ownerSVGElement);
208209
}
209210

210-
function getHref() {
211-
// return a href without hash
212-
const a = document.createElement('a');
213-
a.href = '';
211+
function getHref(doc: Document, customHref?: string) {
212+
let a = cachedDocument.get(doc);
213+
214+
if (!a) {
215+
a = doc.createElement('a');
216+
cachedDocument.set(doc, a);
217+
}
218+
219+
// this is needed to work with SPA
220+
a.href = './clear-current'; // needed to reset previous state
221+
a.href = ''; // reset to current URL (without the previous one, the URL is not updated)
222+
223+
if (customHref) a.href = customHref;
224+
214225
return a.href;
215226
}
216227

@@ -242,7 +253,7 @@ export function transformAttribute(
242253
} else if (name === 'srcset') {
243254
return getAbsoluteSrcsetString(doc, value);
244255
} else if (name === 'style') {
245-
return absoluteToStylesheet(value, getHref());
256+
return absoluteToStylesheet(value, getHref(doc));
246257
} else if (tagName === 'object' && name === 'data') {
247258
return absoluteToDoc(doc, value);
248259
}
@@ -565,7 +576,7 @@ function serializeTextNode(
565576
n,
566577
);
567578
}
568-
textContent = absoluteToStylesheet(textContent, getHref());
579+
textContent = absoluteToStylesheet(textContent, getHref(document));
569580
}
570581
if (isScript) {
571582
textContent = 'SCRIPT_PLACEHOLDER';
@@ -659,7 +670,7 @@ function serializeElementNode(
659670
(n as HTMLStyleElement).sheet as CSSStyleSheet,
660671
);
661672
if (cssText) {
662-
attributes._cssText = absoluteToStylesheet(cssText, getHref());
673+
attributes._cssText = absoluteToStylesheet(cssText, getHref(doc));
663674
}
664675
}
665676
// form fields

0 commit comments

Comments
 (0)