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.
If an element was blocked, its child nodes should also be blocked.
The interactions and mutations on the element and its child nodes
also need to be blocked.
This patch include a breaking change to the recorder's event data.
We used to consider mirror.getId will always return the id of the
target node because we keep serialize every node. But if we call
mirror.getId before serialization then bug happened. This could
happen when we get nextId of newly added nodes if its next sibling
was also newly added.
So we have to return -1 as the id of node which was not serialized
and when we building added nodes in the replayer we should handle
this.
For example, nodes el1, el2 were added together and el1's nextId
will be -1 since el2 was not serialized at that moment. Now we
call el1 as a 'missing next node' and not append it into the DOM
tree after building, instead we store it in a missingNextNodeMap.
After a added node in the same mutation was successfully appened
we will check whether it has a previous id and the id was pointed
to some nodes in the map, if so, we will insert that node before
it and delete the node from map.