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

Reduce rerendering on startup #12847

Merged
merged 5 commits into from
Dec 21, 2018
Merged

Conversation

sgomes
Copy link
Contributor

@sgomes sgomes commented Dec 13, 2018

Description

Small tweaks that result in less unnecessary work during startup. This is a very modest speed improvement (after the changes, the time spent in JS during startup goes down by about 3-5%), but it doesn't introduce much additional complexity at just 2 lines of code.

How has this been tested?

Unit tests, ad-hoc testing. Changes are minor and easy to analyse.

For performance measuring, I tried to create as stable an environment as possible on my local machine (with as few applications running as possible), throttled the CPU by 6x, and ran startup profiles for a large post with many blocks, repeatedly. For each of these runs, I measured how much time the sum of the two long frames during startup took.

image

Types of changes

Ensure viewport calculations happen synchronously instead of waiting on event loop.

We need to call flush, so that the changes happen synchronously, rather than asynchronously, on the next event loop. This avoids the re-rendering of all BlockListBlock instances during startup.

Ensure state.hasUploadPermissions is always a boolean.

The reducer for this property defaults to an empty object, which not only is incorrect (since this is a boolean), but also causes unnecessary re-renders by changing reference. By defaulting to true instead, we fix both problems.

Checklist:

  • My code is tested.
  • My code follows the WordPress code style.
  • My code follows the accessibility standards.
  • My code has proper inline documentation.

refs #11782

@sgomes sgomes added the [Type] Performance Related to performance efforts label Dec 13, 2018
@sgomes sgomes requested review from youknowriad and aduth December 13, 2018 16:32
@sgomes
Copy link
Contributor Author

sgomes commented Dec 13, 2018

Tests seem to be failing due to a configuration issue with phpcs.

@@ -178,5 +178,5 @@ export function isPreviewEmbedFallback( state, url ) {
* @return {boolean} Upload Permissions.
*/
export function hasUploadPermissions( state ) {
return state.hasUploadPermissions;
return !! state.hasUploadPermissions;
Copy link
Member

Choose a reason for hiding this comment

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

What's the reason for this change? This should be something where, if we're expecting it to be a boolean, it should be forced to be a boolean in the reducer logic, not derived by the selector.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was reluctant to make the change in the reducer, as it seemed more prone to create unintended side-effects, in case something is relying on the "objectness" of this part of the state tree. I'm happy to shift the change there if that's what you feel is best, though.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Force-pushed this change. This is now handled at the reducer level where we default to true instead of {}. I chose true instead of false, since {} is a truthy value, and this should thus maintain existing behaviour.

Copy link
Member

Choose a reason for hiding this comment

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

I'm guessing the previous implementation was a result of some bad copypasta from other reducers. A reducer value prefixed with "has" should almost certainly hold a boolean value.

Were there unit tests which should be updated as part of the change? Can there be, if not? 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, this particular reducer didn't seem to have any unit tests. I added a couple :)

@sgomes sgomes force-pushed the perf/reduce-rerendering-on-startup branch 3 times, most recently from e7ae814 to 0e88f4e Compare December 13, 2018 18:01
@aduth
Copy link
Member

aduth commented Dec 14, 2018

  • Ensure selector returns a primitive type instead of a changing object reference

Could you elaborate on why this change was made? I mean, it seems like a perfectly correct fix, just not sure how it relates to the performance work.

@aduth
Copy link
Member

aduth commented Dec 14, 2018

I might expect it having something to do with the fact that state "changed" previously (from {} to true)? Which would cascade to subscribers (potentially many bound components)? Related reading if you're interested on the front of "oh wow we do a lot of state changes during initialization": #12877.

Copy link
Member

@aduth aduth left a comment

Choose a reason for hiding this comment

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

LGTM 👍

I added some CHANGELOG entries for the affected packages, which we should be more in the habit of doing to inform the package publisher on the sorts of changes included (in selecting major, minor, patch).

@sgomes
Copy link
Contributor Author

sgomes commented Dec 14, 2018

I might expect it having something to do with the fact that state "changed" previously (from {} to true)? Which would cascade to subscribers (potentially many bound components)? Related reading if you're interested on the front of "oh wow we do a lot of state changes during initialization": #12877.

That's exactly why, yes, sorry I wasn't very clear in the issue. The commit message had more details; I'll copy them over to the issue for reference.

@sgomes
Copy link
Contributor Author

sgomes commented Dec 14, 2018

@aduth Thanks for the link to #12877! That's a lot better than any startup optimisations opportunities I've found so far, which tended to have a nice large impact in development mode, but next to nothing in production (I assume this has to do with the time it takes to do the extra logging that takes place in development).

Also, thanks for adding the changelog commits!

@youknowriad youknowriad added this to the 4.8 milestone Dec 21, 2018
sgomes and others added 5 commits December 21, 2018 10:53
We need to call `flush`, so that the changes happen synchronously,
rather than asynchronously, on the next event loop.
This avoids the re-rendering of all `BlockListBlock` instances
during startup.
The reducer for this property defaults to an empty object, which
not only is incorrect (since this is a boolean), but also causes
unnecessary re-renders by changing reference. By defaulting to
`true` instead, we fix both problems.
@youknowriad youknowriad force-pushed the perf/reduce-rerendering-on-startup branch from 943b054 to b44bc8f Compare December 21, 2018 09:53
@youknowriad youknowriad merged commit 73b1a4f into master Dec 21, 2018
@youknowriad youknowriad deleted the perf/reduce-rerendering-on-startup branch December 21, 2018 10:17
youknowriad pushed a commit that referenced this pull request Jan 3, 2019
* Ensure viewport data store changes happen immediately on startup.

We need to call `flush`, so that the changes happen synchronously,
rather than asynchronously, on the next event loop.
This avoids the re-rendering of all `BlockListBlock` instances
during startup.

* Ensure `state.hasUploadPermissions` is always a boolean.

The reducer for this property defaults to an empty object, which
not only is incorrect (since this is a boolean), but also causes
unnecessary re-renders by changing reference. By defaulting to
`true` instead, we fix both problems.

* Add a couple of tests for hasUploadPermissions reducer.

* Core Data: Add CHANGELOG entry for hasUplaodPermissions boolean fix

* Viewport: Add CHANGELOG entry for synchronous assignment
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.

3 participants