* fix: elements would lose some state like scroll position because of "virtual parent" optimization
* refactor: the bugfix code
bug: elements would lose some state like scroll position because of "virtual parent" optimization
* fix: an error occured at applyMutation(remove nodes part)
error message:
Uncaught (in promise) DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node
Loop the append queue has been proved to be very inefficient, and
some times lead to N^2 time complexity.
Especially when some abnormal data could not be appended into the
real DOM, will make a dead loop.
Previously we use a 5000ms time out to handle this, which is not
user-friendly and not explicitly.
In this patch, we transform the queue into a tree data structure,
which reflects the layout of real DOM. With the tree data structure,
we can find whether there are dangling nodes that need to be dropped.
Also, the iteration will be much more efficient.
There is still a 500ms time out to avoid a dead loop, but should not
be called in expected scenarios.
* record canvas mutations
close#60, #261
This patch implements the canvas mutation observer.
It consists of both the record and the replay side changes.
In the record side, we add a `recordCanvas` flag to indicate
whether to record canvas elements and the flag defaults to false.
Different from our other observers, the canvas observer was
disabled by default. Because some applications with heavy canvas
usage may emit a lot of data as canvas changed, especially the
scenarios that use a lot of `drawImage` API.
So the behavior should be audited by users and only record canvas
when the flag was set to true.
In the replay side, we add a `UNSAFE_replayCanvas` flag to indicate
whether to replay canvas mutations.
Similar to the `recordCanvas` flag, `UNSAFE_replayCanvas` defaults
to false. But unlike the record canvas implementation is stable and
safe, the replay canvas implementation is UNSAFE.
It's unsafe because we need to add `allow-scripts` to the replay
sandbox, which may cause some unexpected script execution. Currently,
users should be aware of this implementation detail and enable this
feature carefully.
* update canvas integration test
- What was broken was that it would just play activity from the first page view, but then would stop at the second page view (meta) as actions after that had been discarded
- This restores the functionality given by the comment 'return the events from last meta to the end.' - we never want to discard events that are after the baseline time
- I believe 'session' is the incorrect terminology for this function name, as a session in web analytics usually means a series of page views
related to #6
Since the currently 'play at any time offset' implementation is pretty simple,
there are many things we can do to optimize its performance.
In this patch, we do the following optimizations:
1. Ignore some of the events during fast forward.
For example, when we are going to fast forward to 10 minutes later,
we do not need to perform mouse movement events during this period.
2. Use a fragment element as the 'virtual parent node'.
So newly added DOM nodes will be appended to this fragment node,
and finally being appended into the document as a batch operation.
These changes reduce a lot of time which was spent on reflow/repaint previously.
I've seen a 10 times performance improvement within these approaches.
And there are still some things we can do better but not in this patch.
1. We can build a virtual DOM tree to store the mutations of DOM.
This will minimize the number of DOM operations.
2. Another thing that may help UX is to make the fast forward process async and cancellable.
This may make the drag and drop interactions in the player's UI looks smooth.
On recordings with many full pageloads, dom state and mutations were being applied only to be discarded when a new pageload came in, resulting in very slow time to rebuild - and inability to interactively 'scrub' through these recordings