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

[Flare] Update interactiveUpdates flushing heuristics #15687

Merged
merged 14 commits into from May 21, 2019

Conversation

trueadm
Copy link
Contributor

@trueadm trueadm commented May 20, 2019

This PR changes the logic that occurs in interactiveUpdates, to account for a scenario that proved problematic in the testing of React Flare – the mixing of both event systems on the same app. Note: this change is behind the experimental event API. Also included in this PR are:

  • interactiveUpdates -> discreteUpdates
  • flushInteractiveUpdates -> flushDiscreteUpdates
  • Adds batchedEventUpdates and a new BatchedEventPhase to scheduler

Discrete events use timeStamp to manage flushing

Now that the Flare event system and the existing event system co-exists, we've noticed far more flushing is occurring; which is problematic for cases where this behaviour was non-existant with only the existing event system. To counter this a timeStamp heuristic has been added by reading the timeStamp from the window object. We will probably want to change this to be an argument (rather than reading from window) in the future, but I didn't want to introduce too many changes in this PR.

The timeStamp is an important field on events, as it allows us to tell what events were part of the same real-world interaction. For example: mouseup, pointerup and click all should have the same timeStamp. If we know that they're all the same timeStamp, we can do a single flush for them all, which improves compatibility with Flare and also should improve runtime performance as we're flushing sync less.

@sizebot
Copy link

sizebot commented May 20, 2019

ReactDOM: size: 🔺+0.2%, gzip: 🔺+0.2%

Details of bundled changes.

Comparing: 31487dd...52ffb56

react-dom

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-dom.development.js +0.3% +0.3% 847.08 KB 849.6 KB 193.06 KB 193.66 KB UMD_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.2% 105.12 KB 105.36 KB 34.15 KB 34.23 KB UMD_PROD
react-dom.profiling.min.js +0.2% +0.3% 108.27 KB 108.52 KB 35.16 KB 35.26 KB UMD_PROFILING
react-dom.development.js +0.3% +0.3% 841.39 KB 843.92 KB 191.49 KB 192.09 KB NODE_DEV
react-dom.production.min.js 🔺+0.2% 🔺+0.2% 105.11 KB 105.36 KB 33.55 KB 33.62 KB NODE_PROD
react-dom.profiling.min.js +0.2% +0.2% 108.46 KB 108.7 KB 34.44 KB 34.52 KB NODE_PROFILING
ReactDOM-dev.js +0.3% +0.3% 866.86 KB 869.41 KB 193.07 KB 193.67 KB FB_WWW_DEV
ReactDOM-prod.js 🔺+0.3% 🔺+0.4% 353.02 KB 354.12 KB 65.32 KB 65.55 KB FB_WWW_PROD
ReactDOM-profiling.js +0.3% +0.3% 358 KB 359.11 KB 66.31 KB 66.54 KB FB_WWW_PROFILING
react-dom-unstable-fire.development.js +0.3% +0.3% 847.42 KB 849.94 KB 193.21 KB 193.81 KB UMD_DEV
react-dom-unstable-fire.production.min.js 🔺+0.2% 🔺+0.2% 105.13 KB 105.38 KB 34.15 KB 34.24 KB UMD_PROD
react-dom-unstable-fire.profiling.min.js +0.2% +0.3% 108.29 KB 108.54 KB 35.17 KB 35.28 KB UMD_PROFILING
react-dom-unstable-fire.development.js +0.3% +0.3% 841.74 KB 844.26 KB 191.64 KB 192.23 KB NODE_DEV
react-dom-unstable-fire.production.min.js 🔺+0.2% 🔺+0.2% 105.13 KB 105.37 KB 33.56 KB 33.63 KB NODE_PROD
react-dom-unstable-fire.profiling.min.js +0.2% +0.2% 108.47 KB 108.72 KB 34.45 KB 34.53 KB NODE_PROFILING
ReactFire-dev.js +0.3% +0.3% 866.07 KB 868.62 KB 193 KB 193.63 KB FB_WWW_DEV
ReactFire-prod.js 🔺+0.3% 🔺+0.3% 340.99 KB 342.1 KB 62.92 KB 63.14 KB FB_WWW_PROD
ReactFire-profiling.js +0.3% +0.4% 345.95 KB 347.05 KB 63.88 KB 64.11 KB FB_WWW_PROFILING
react-dom-test-utils.production.min.js 0.0% -0.0% 10.76 KB 10.76 KB 3.95 KB 3.94 KB UMD_PROD
react-dom-unstable-native-dependencies.development.js 0.0% -0.0% 60.76 KB 60.76 KB 15.85 KB 15.85 KB UMD_DEV
react-dom-unstable-native-dependencies.production.min.js 0.0% -0.0% 10.43 KB 10.43 KB 3.57 KB 3.57 KB NODE_PROD
react-dom-server.browser.production.min.js 0.0% 0.0% 19.2 KB 19.2 KB 7.23 KB 7.23 KB UMD_PROD
react-dom-server.node.production.min.js 0.0% 0.0% 19.98 KB 19.98 KB 7.53 KB 7.53 KB NODE_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.1% 1.21 KB 1.21 KB 707 B 706 B UMD_PROD
react-dom-unstable-fizz.browser.production.min.js 0.0% -0.2% 1.05 KB 1.05 KB 638 B 637 B NODE_PROD
react-dom-unstable-fizz.node.production.min.js 0.0% -0.1% 1.1 KB 1.1 KB 668 B 667 B NODE_PROD

react-native-renderer

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
ReactNativeRenderer-dev.js +0.1% +0.1% 656.5 KB 656.99 KB 139.82 KB 139.89 KB RN_FB_DEV
ReactNativeRenderer-prod.js 🔺+0.1% 0.0% 249.21 KB 249.35 KB 43.37 KB 43.38 KB RN_FB_PROD
ReactNativeRenderer-profiling.js +0.1% +0.1% 256.95 KB 257.09 KB 44.98 KB 45 KB RN_FB_PROFILING
ReactNativeRenderer-dev.js +0.1% +0.1% 656.42 KB 656.9 KB 139.78 KB 139.85 KB RN_OSS_DEV
ReactNativeRenderer-prod.js 🔺+0.1% 0.0% 249.23 KB 249.37 KB 43.36 KB 43.38 KB RN_OSS_PROD
ReactNativeRenderer-profiling.js +0.1% +0.1% 256.96 KB 257.11 KB 44.98 KB 45 KB RN_OSS_PROFILING
ReactFabric-dev.js +0.1% +0.1% 645.26 KB 645.74 KB 137.08 KB 137.16 KB RN_FB_DEV
ReactFabric-prod.js 🔺+0.1% 0.0% 242.41 KB 242.55 KB 42.04 KB 42.06 KB RN_FB_PROD
ReactFabric-profiling.js +0.1% +0.1% 250.16 KB 250.3 KB 43.69 KB 43.72 KB RN_FB_PROFILING
ReactFabric-dev.js +0.1% +0.1% 645.16 KB 645.65 KB 137.04 KB 137.13 KB RN_OSS_DEV
ReactFabric-prod.js 🔺+0.1% 0.0% 242.41 KB 242.55 KB 42.03 KB 42.05 KB RN_OSS_PROD
ReactFabric-profiling.js +0.1% +0.1% 250.17 KB 250.31 KB 43.69 KB 43.72 KB RN_OSS_PROFILING

react-reconciler

File Filesize Diff Gzip Diff Prev Size Current Size Prev Gzip Current Gzip ENV
react-reconciler.development.js +0.1% +0.1% 510.99 KB 511.47 KB 108.57 KB 108.62 KB NODE_DEV
react-reconciler.production.min.js 🔺+0.2% 0.0% 62.79 KB 62.9 KB 18.83 KB 18.83 KB NODE_PROD
react-reconciler-persistent.development.js +0.1% 0.0% 508.67 KB 509.15 KB 107.57 KB 107.62 KB NODE_DEV
react-reconciler-persistent.production.min.js 🔺+0.2% 0.0% 62.8 KB 62.91 KB 18.84 KB 18.84 KB NODE_PROD
react-reconciler-reflection.production.min.js 0.0% -0.1% 2.51 KB 2.51 KB 1.12 KB 1.11 KB NODE_PROD

Generated by 🚫 dangerJS

@trueadm trueadm changed the title [Flare] Change interactiveUpdates heuristics when handling events [Flare] Update interactiveUpdates flushing heuristics May 20, 2019
@acdlite
Copy link
Collaborator

acdlite commented May 20, 2019

Also how confident are we that this works in non-Chrome browsers?

@trueadm
Copy link
Contributor Author

trueadm commented May 20, 2019

@acdlite I checked it Safari, FF, Chrome and Edge. All looking good with this change. I need to confirm with IE, but this is behind a flag anyway, so there should be no immediate risk.


dispatchEvent('pointerdown', 100);
dispatchEvent('pointerup', 100);
// Ensure the timeStamp logic works
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the Press event component the best place to test this logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It’s fine for now. All responders should have some variant of this too.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's that the changes are being made to the core but the tests are here. And those tests have __DEV__-specific results

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can follow up after and make tests in core too. I don't want to block this any longer given I'm on PTO in a few days. Maybe we can add this to our TODO list otherwise.

@acdlite
Copy link
Collaborator

acdlite commented May 20, 2019

Can you add a test for:

ReactDOM.unstable_batchedUpdates(() => {
  // This should flush synchronously
  ReactDOM.unstable_flushDiscreteUpdates();
  setState();
});

Or replace batchedUpdates with a click handler:

function onClick() {
  // This should flush synchronously
  ReactDOM.unstable_flushDiscreteUpdates();
  setState();
};

I believe your current implementation of flushDiscreteUpdates would fail that test. See #15687 (comment) for suggested implementation.

@acdlite
Copy link
Collaborator

acdlite commented May 20, 2019

Might also want to add a test case that includes an imperative el.click() inside an effect.

@acdlite
Copy link
Collaborator

acdlite commented May 20, 2019

Per our chat thread, I'd also be OK with adding a TODO above the early return for BatchPhase to remind ourselves to come back to it.

@trueadm
Copy link
Contributor Author

trueadm commented May 21, 2019

I've added more tests, updated tests, added BatchedEventPhase and also did various other things to tidy up the code.

@trueadm trueadm requested a review from acdlite May 21, 2019 00:33
// TODO: Should we fire a warning? This happens if you synchronously invoke
// an input event inside an effect, like with `element.click()`.
export function flushDiscreteUpdates() {
if (workPhase === CommitPhase || workPhase === BatchedPhase) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this a no-op in batchedUpdates? Is there a test that failed otherwise?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, a bunch of tests failed from memory.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you put a TODO there? I'll take a look later. Doesn't have to block merge.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added a TODO. Let's resync with this once I'm back from PTO; this at least unblocks us internally.

@tjallingt
Copy link
Contributor

I've previously encountered some issues related to Event.timeStamp in Vue with forks of older Chrome versions (specifically QtWebEngine) where the timeStamp would be some very large negative number.

Might be interesting to take a look at these:

vuejs/vue#9681
vuejs/vue@7591b9d
https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/modules/events.js#L42-L90

@trueadm
Copy link
Contributor Author

trueadm commented May 21, 2019

I saw some prior issues in Firefox, where the time stamps where using different precision timers (this longer numbers for some events than others). However, unlike Vue, we only care that the time stamps match or do not match – so their precision doesn't matter (even if they are negative). If the timeStamp is 0, we bail back to less optimal behaviour.

@acdlite
Copy link
Collaborator

acdlite commented May 21, 2019

^ We need to think about this heuristic more before we ship this to open source but since this is gated behind the Flare feature flag, it's good to merge so we can test it internally.

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.

None yet

6 participants