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

Extract the attributes from the editor's state shape to enhance performance #12268

Closed
wants to merge 1 commit into from

Conversation

youknowriad
Copy link
Contributor

Implements #11782 (comment)

I did notice better performance while typing on blocks.

The PR still needs some polish but it's ready to be tested.

cc @sgomes @gziolo

@youknowriad youknowriad added the [Type] Performance Related to performance efforts label Nov 24, 2018
@youknowriad youknowriad added this to the 4.6 milestone Nov 24, 2018
@sgomes
Copy link
Contributor

sgomes commented Nov 24, 2018

Thanks, @youknowriad ! I've got a similar set of changes I'm working on, and are nearly done save for the tests, which still need some fixes. I also modified some of the other selectors to not rely on attributes, wherever possible, and added some memoization here and there.

For improvements, I measured 30% better results before I started fixing the tests; I'll run some benchmarks again once I'm finished there.

Shall I post a WIP of this on Monday so that we can compare PRs and decide which one to go with?

@youknowriad
Copy link
Contributor Author

Sure, just push your PR when you're ready. My PR is very basic, just applying the root idea to check the impact without any other improvements. Happy to continue based on your work.

Copy link
Member

@noisysocks noisysocks left a comment

Choose a reason for hiding this comment

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

The approach makes a lot of sense to me, and I am seeing a 1.6x (18 ms to 11 ms) reduction in time spent evaluating JavaScript while processing keypress events which is super encouraging.

I'm reluctant to include this in 5.0 since this has the potential to introduce unexpected regressions very late into the release process.

I'm seeing a few bugs when I test locally.


Pressing Backspace causes blocks to unexpectedly merge

backspace

  1. Create a new post
  2. Type some text
  3. Press Enter to create a new paragraph
  4. Type some more text
  5. Press Backspace

Expected result: The last character should be deleted.
Actual result: The two paragraph blocks merge.

Autosaves fail

  1. Create a new post
  2. Type some text
  3. Without deselecting the block, wait for an autosave to happen

Expected result: The post should autosave.
Actual result: The autosave fails and an Updating failed message appears.

Changing an existing block does not mark the post as dirty

  1. Create a new post
  2. Enter a title
  3. Type some text into the initial paragraph block
  4. Deselect the block
  5. Click Save Draft
  6. Re-select the block and modify its text

Expected result: The Save Draft button should become active.
Actual result: The Save Draft button remains disabled.

The / inserter no longer works

  1. Create a new post
  2. Select the initial paragraph block
  3. Type /

Expected result: The block autocompleted should appear.
Actual result: A / is typed and nothing else.

}

return flattenedBlockAttributes;
}
Copy link
Member

Choose a reason for hiding this comment

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

getFlattenedBlocks and getFlattenedBlockAttributes are very similar. They're both functions that flatten a block tree into a hash map. The only difference is what is stored in the map. Could we use a higher order function that leaves it up to the caller to decide what is stored in the map?

function flattenBlocks( blocks, iteratee ) {
	const result = {};

	const stack = [ ...blocks ];
	while ( stack.length ) {
		const { innerBlocks, ...block } = stack.shift();
		stack.push( ...innerBlocks );
		result[ block.clientId ] = iteratee( block );
	}

	return result;
}

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it would be much cleaner 👍

...state,
[ action.clientId ]: {
...state[ action.clientId ],
...omit( action.updates, 'attributes' ),
Copy link
Member

Choose a reason for hiding this comment

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

We don't need to call omit() again here.

Suggested change
...omit( action.updates, 'attributes' ),
...changes,

}

const changes = omit( action.updates, 'attributes' );
if ( keys( changes ).length === 0 ) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: We could use _.isEmpty() here, though not sure how it affects performance.

if ( isEmpty( changes ) ) {

@@ -1947,7 +1948,8 @@ export const getInserterItems = createSelector(
},
( state, rootClientId ) => [
state.blockListSettings[ rootClientId ],
state.editor.present.blocks,
state.editor.present.blocks.byClientId,
state.editor.present.blocks.order,
Copy link
Member

Choose a reason for hiding this comment

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

Nice —this should help a lot! 🔥

Copy link
Member

Choose a reason for hiding this comment

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

Does order matter for the inserter items? Can we reason differently about nested blocks where it could have an impact? Do I miss anything?

}

return flattenedBlockAttributes;
}
Copy link
Member

Choose a reason for hiding this comment

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

Yes, it would be much cleaner 👍

@@ -1947,7 +1948,8 @@ export const getInserterItems = createSelector(
},
( state, rootClientId ) => [
state.blockListSettings[ rootClientId ],
state.editor.present.blocks,
state.editor.present.blocks.byClientId,
state.editor.present.blocks.order,
Copy link
Member

Choose a reason for hiding this comment

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

Does order matter for the inserter items? Can we reason differently about nested blocks where it could have an impact? Do I miss anything?

@@ -1981,7 +1983,8 @@ export const hasInserterItems = createSelector(
},
( state, rootClientId ) => [
state.blockListSettings[ rootClientId ],
state.editor.present.blocks,
state.editor.present.blocks.order,
state.editor.present.blocks.byClientId,
Copy link
Member

Choose a reason for hiding this comment

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

The same about the order as above.

@youknowriad
Copy link
Contributor Author

Closing in favor of #12312

@youknowriad youknowriad deleted the update/change-editor-state-shape branch November 26, 2018 17:40
@gziolo gziolo removed this from the 4.6 milestone Nov 29, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants