-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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: optimize the performance of processMutations #1187
Conversation
🦋 Changeset detectedLatest commit: 3557938 The changes in this PR will be included in the next version bump. This PR includes changesets to release 7 packages
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 |
76aa2a7
to
7960f18
Compare
df1d889
to
3557938
Compare
Hey @wfk007 this is a great performance improvement, thank you so much for putting all the hard work into this. |
I haven't looked too closely but the change is nice and small and seems to make sense. |
@Juice10 @eoghanmurray I have been trapped at work and complex trivial things in life recently, and I will add a benchmark test and fix the Lint error later, thanks for your review and great suggestions. |
@Juice10 @eoghanmurray Hi, I plan to separate this PR into two, thanks for your great suggestions again part one: #1214 part two: #1220 |
processMutations
contains two phases:and they have bad performance in some cases.
processMutation
case
In the case below: (reproduce link: https://github.com/wfk007/test-processMutation)
we create 1000 ElementNode and insert them into
#target
, each Node is the parent of the following Nodeperformance
WITHOUT
record
, it takes about 50ms to renderWITH
record
it takes 655ms and processMutation takes 604msreason
The dom structure below can be created in many ways:
Approach 1:
Browser Mutation observer callback result:
approach 2:
Browser Mutation observer callback result:
In order to cover different Mutation observer callback results and track adds/removes Nodes, RRweb loops all mutations and its'
addedNodes
.Each Node in
addedNodes
will still travel all its' childNodes.Considering approach2 result:
travel E1
travel E2(which is the childNode of E1)
travel E2(no need to travel E2 and its' childNodes again)
solution
In
genAdds
, if the node is added toaddedSet
ormovedSet
, there is no need to travel it and its' children againafter optimizing, it takes 160ms and processMutation takes 77ms
emit
case
(case is on the way)
performance
when the size of addedSet is huge(20k+ Nodes), the for-loop is very slow with time complexity O(n^2) to find a valid Node
reason
There are 20000 nodes in addList, and index 900 is the first valid Node from right to left, but its' previous is not a valid Node. we loop from right to left to find the first valid Node
It is very very slow(takes about 16s).
solution
I create a linkedNodeList based on DoubleLinkedList to accelerate node query with array index, and query time complexity decrease from O(n) to O(1) with a huge performance boost