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

Store operations as plain JS objects in History #1576

Closed
wants to merge 1 commit into from

Conversation

bengotow
Copy link
Contributor

Hey! This PR is a suggested mitigation for #1402 and reduces the memory overhead of keeping a large undo stack by converting the Operation objects in History to plain JS (and stripping the __cache field used for memoization.)

In order to make this change, I removed the selection paths from the JSON representation in favor of the keys in the underlying Range. I'm not sure what the motivation is for storing them as paths (maybe an experiment toward #1408? maybe support for collaborative editing?) Because the serialized and deserialized Selection objects no longer have value.document, they can't perform the coercion from path to key and vice versa.

To implement this and keep the added benefits of using paths, I think the best move (long term at least) is to fully implement #1408, since using paths everywhere would also eliminate the need for value.document and the conversion.

Outcomes

Test Scenario:

  • Launch app
  • Open editor
  • Start profiler
  • Type "A" followed by "Backspace" 20 times
  • Stop profiler

Note that in both results below the memory usage is growing because we haven't hit the undo limit, so we're storing more and more data with every keystroke. It's just that in the after scenario we're storing so little it appears it's not growing.

Before:
screen shot 2018-01-30 at 4 29 16 pm

After:
screen shot 2018-01-30 at 4 27 02 pm

@justinweiss
Copy link
Collaborator

justinweiss commented Jan 31, 2018

This is really great, but it doesn't seem quite right to serialize keys, because keys only make sense on a specific live version of a document. All of the other operations only carry around paths, so it would make more sense to me to turn the Selection keys into paths when it's serialized.

I don't think that would affect the behavior -- if you're not working collaboratively, paths will always be valid on the document they generated. Well, unless you ran some changes with save:false, but all bets are pretty much off at that point :-)

@bengotow
Copy link
Contributor Author

bengotow commented Jan 31, 2018

Hmmm I think you're right - with this change in place, it becomes impossible to save the editor state with the undo history, restore it later from JSON, and re-create selection changes, since the keys would be different when the document was re-created.

I think a possible solution would be for the undo and redo Change methods to provide the Operation with a document, allowing it to do the mapping from the saved anchorPath to an anchorKey in the active document. Come to think of it, I'm not sure when/where the operations in the stack get a value when the document is re-inflated. Not sure how this worked before :-)

@justinweiss
Copy link
Collaborator

I don’t think they do! Luckily, you can reconstruct it if you really wanted to — the top operation on the stack has the value, apply(current value, invert(operation)), the next one has apply(just calculated value, invert(operation)), and so on. The way I remember it is, the operation should always contain the value it was sourced from, and you should always be able to apply an operation to its own value.

Actually, if I remember right, Slate doesn’t recalculate the value when it inverts the rest of the operation, which could cause some problems.

@ianstormtaylor
Copy link
Owner

Fixed by #3093.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants