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

perf(snapshot): avoid recreate element a every time #1387

Merged
merged 4 commits into from
May 2, 2024

Conversation

H4ad
Copy link
Contributor

@H4ad H4ad commented Jan 4, 2024

Avoid recreating the same element every time, instead, we cache and we just update the element.

Before: 779k ops/s
After: 860k ops/s

Benchmark: https://jsbench.me/ktlqztuf95/1

On Chrome:
image

On Firefox:
image

Copy link

changeset-bot bot commented Jan 4, 2024

🦋 Changeset detected

Latest commit: d21a234

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 8 packages
Name Type
rrweb-snapshot Patch
rrweb Patch
rrdom Patch
rrdom-nodejs Patch
rrweb-player Patch
@rrweb/types Patch
@rrweb/web-extension Patch
rrvideo Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@H4ad H4ad changed the title perf(snapshot): avoid recreate element a everytime perf(snapshot): avoid recreate element a every time Jan 4, 2024
@H4ad H4ad force-pushed the perf/avoid-create-element-a branch from f75e801 to f41bf19 Compare January 5, 2024 01:14
@H4ad H4ad force-pushed the perf/avoid-create-element-a branch from f41bf19 to 44db8d7 Compare January 12, 2024 23:17
@eoghanmurray
Copy link
Contributor

eoghanmurray commented Feb 2, 2024

Could you also test the following possibility: [edit: this was much slower]

function getHref(doc: Document) {
  // return a href without hash
  const url = new URL(doc.location.href);
  url.hash = ''
  return url.href;
}

Some more work would need to be done to support the new customHref case so maybe this PR is fine

@eoghanmurray
Copy link
Contributor

I've a version which should perform just as good without the need for caching in #1434

@H4ad would you like to run benchmarks on that?

@H4ad
Copy link
Contributor Author

H4ad commented Mar 29, 2024

@eoghanmurray Sorry for taking so long to answer, I will run the benchmarks as soon I can and I will bring back the results

@eoghanmurray
Copy link
Contributor

(in case you miss the thread further up)

Could you cherry-pick eoghanmurray@615e164

And also rebase or merge master

@H4ad H4ad force-pushed the perf/avoid-create-element-a branch from 44db8d7 to e36bc9d Compare April 2, 2024 23:40
@H4ad
Copy link
Contributor Author

H4ad commented Apr 2, 2024

@eoghanmurray Done!

@eoghanmurray
Copy link
Contributor

I've added another review comment as I'd like to be able to recreate the SPA scenario via a test which necessitates the cache bust. I created a test case but was not able to recreate the scenario where the cache bust is needed.

@H4ad
Copy link
Contributor Author

H4ad commented Apr 7, 2024

@eoghanmurray did you submit the review?

@eoghanmurray
Copy link
Contributor

eoghanmurray commented Apr 11, 2024

I've added another review comment

This is what I was referring to:
https://github.com/rrweb-io/rrweb/pull/1387/files#diff-6434d77e679a3d1e4217dcad03ee6f02551e41dc0b077a06a45020e68e1b4ee3R222

Here is the test I was talking about, which could be cherry-picked in here, but basically it doesn't demonstrate any need for the ./clear-current stuff, so maybe you can enhance the test case?
eoghanmurray@4d52165

And here's a refactoring of how to 'clear the cache' so that it only does it if there is an old A element, and if it's value is different to the incoming value:
eoghanmurray@38e677a

@eoghanmurray
Copy link
Contributor

I propose merging a version of my changes:
38e677a

but without the This is needed for SPAs. bit as we don't yet have any evidence that that is necessary.

@H4ad H4ad force-pushed the perf/avoid-create-element-a branch from e36bc9d to 20c9fe8 Compare April 26, 2024 14:34
@H4ad
Copy link
Contributor Author

H4ad commented Apr 26, 2024

You are right, I don't know if it was a bug on Chrome when I tested but the behavior that I described in the comment is not true anymore.

I have updated the code to reflect your changes and I also removed those comments/code about SPA.

Thanks for the patience, I was very lazy on this PR.

packages/rrweb-snapshot/src/snapshot.ts Show resolved Hide resolved
@@ -565,7 +587,7 @@ function serializeTextNode(
n,
);
}
textContent = absoluteToStylesheet(textContent, getHref());
textContent = absoluteToStylesheet(textContent, getHref(document));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming this is 'more correct' if the doc parameter is passed down via serializeTextNode; but I haven't checked the consequences of that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, I think we need to use options.doc (and pass in doc in the options).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've passed in via options.doc in #1434

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that #1434 is not a goer, could you cherry pick the following commit which improves the issue raised in this thread:
eoghanmurray@615e164

packages/rrweb-snapshot/src/snapshot.ts Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Outdated Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Outdated Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Outdated Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Outdated Show resolved Hide resolved
packages/rrweb-snapshot/src/snapshot.ts Outdated Show resolved Hide resolved
@eoghanmurray
Copy link
Contributor

Would you be able to cherry pick eoghanmurray@4d52165 as I think it still has worth in the event of this implementation being changed in future.

(Although 'Maintainers are allowed to edit this pull request' is checked, I'm unable to push to your H4ad origin due to other permissions issues)

@eoghanmurray
Copy link
Contributor

Actually I'll just create a new PR for that test case

@eoghanmurray eoghanmurray merged commit 5e7943d into rrweb-io:master May 2, 2024
6 checks passed
@H4ad H4ad deleted the perf/avoid-create-element-a branch May 2, 2024 16:08
@eoghanmurray
Copy link
Contributor

eoghanmurray commented May 3, 2024

@H4ad I found a bug where a blob: style url would be persisted on the cached anchor element and would incorrect return values on subsequent calls to getHref. Fix in #1467

But could you re-review this PR in view of those single page app bugs you previously encountered?

@H4ad
Copy link
Contributor Author

H4ad commented May 3, 2024

Sure, I will try to leave a review as soon as possible.

@eoghanmurray
Copy link
Contributor

Just to note, using URL.canParse can make #1434 more competitve; only ~20% slower in jsbench:

function absoluteToDocCanParse(doc, attributeValue) {
// todo: do we need check if attributeValue is ''? 
    if (URL && URL.canParse(attributeValue)) {
	return new URL(attributeValue, doc.location.href).href;
    } else {
	const a = doc.createElement('a');
	a.setAttribute('href', attributeValue);
	return a.href;
    }
}

jxiwang pushed a commit to amplitude/rrweb that referenced this pull request Jul 31, 2024
perf(snapshot): avoid costly generation of <a> element on each call to `getHref`, instead cache an anchor element and reuse it's href attributed

---------

Co-authored-by: Eoghan Murray <[email protected]>
billyvg added a commit to getsentry/rrweb that referenced this pull request Sep 6, 2024
Merges the following commits:

* [Ensure there is separation of
timestamps](rrweb-io#1455)
* [perf(snapshot): avoid recreate element a every
time](rrweb-io#1387)
* [Fix that blob urls persist on the shared anchor element and can't be
later modified](rrweb-io#1467)
* [yarn format - prettier improvements & add
.editorconfig](rrweb-io#1471)
* [Fixup for background-clip
replacement](rrweb-io#1476)
* [Fix and test for bug](rrweb-io#1481)
jxiwang pushed a commit to amplitude/rrweb that referenced this pull request Oct 16, 2024
perf(snapshot): avoid costly generation of <a> element on each call to `getHref`, instead cache an anchor element and reuse it's href attributed

---------

Co-authored-by: Eoghan Murray <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants