diff --git a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp index c1c8d70167c0..e3d7b7f440cc 100644 --- a/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp +++ b/packages/react-native/ReactCommon/react/nativemodule/webperformance/NativePerformance.cpp @@ -34,6 +34,15 @@ namespace facebook::react { namespace { +/** + * Default `durationThreshold` (in milliseconds) applied to `event` entries when + * the JS API does not provide an explicit value. Per the W3C Event Timing + * spec, observers for `event` entries default to a 104ms threshold: + * https://www.w3.org/TR/event-timing/#sec-modifications-perf-timeline + */ +constexpr HighResDuration DEFAULT_EVENT_DURATION_THRESHOLD = + HighResDuration::fromMilliseconds(104); + class PerformanceObserverWrapper : public jsi::NativeState { public: explicit PerformanceObserverWrapper( @@ -337,7 +346,7 @@ void NativePerformance::observe( } auto durationThreshold = - options.durationThreshold.value_or(HighResDuration::zero()); + options.durationThreshold.value_or(DEFAULT_EVENT_DURATION_THRESHOLD); // observer of type multiple if (options.entryTypes.has_value()) { diff --git a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js index 398ecd712ce7..ab89fd1d4f3a 100644 --- a/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js +++ b/packages/react-native/src/private/webapis/performance/__tests__/EventTimingAPI-itest.js @@ -38,7 +38,7 @@ describe('Event Timing API', () => { const callback = jest.fn(); const observer = new PerformanceObserver(callback); - observer.observe({entryTypes: ['event']}); + observer.observe({type: 'event', durationThreshold: 0}); const root = Fantom.createRoot(); Fantom.runTask(() => { @@ -79,7 +79,7 @@ describe('Event Timing API', () => { const callback = jest.fn(); const observer = new PerformanceObserver(callback); - observer.observe({entryTypes: ['event']}); + observer.observe({type: 'event', durationThreshold: 0}); const SIMULATED_PROCESSING_DELAY = 50; @@ -132,7 +132,7 @@ describe('Event Timing API', () => { const callback = jest.fn(); const observer = new PerformanceObserver(callback); - observer.observe({entryTypes: ['event']}); + observer.observe({type: 'event', durationThreshold: 0}); function MyComponent() { const [count, setCount] = useState(0); @@ -188,7 +188,7 @@ describe('Event Timing API', () => { const callback = jest.fn(); const observer = new PerformanceObserver(callback); - observer.observe({entryTypes: ['event']}); + observer.observe({type: 'event', durationThreshold: 0}); let eventTimeStamp; @@ -341,6 +341,52 @@ describe('Event Timing API', () => { expect(callback).toHaveBeenCalledTimes(1); }); + it('defaults to 104ms for event entries per W3C spec', () => { + const callback = jest.fn(); + + const observer = new PerformanceObserver(callback); + observer.observe({type: 'event'}); + + let forceDelay = false; + + function MyComponent() { + const [count, setCount] = useState(0); + + return ( + { + if (forceDelay) { + sleep(104); + } + setCount(count + 1); + }}> + {count} + + ); + } + + const root = Fantom.createRoot(); + Fantom.runTask(() => { + root.render(); + }); + + const element = nullthrows( + root.document.documentElement.firstElementChild, + ); + + expect(callback).not.toHaveBeenCalled(); + + Fantom.dispatchNativeEvent(element, 'click'); + + expect(callback).toHaveBeenCalledTimes(0); + + forceDelay = true; + + Fantom.dispatchNativeEvent(element, 'click'); + + expect(callback).toHaveBeenCalledTimes(1); + }); + it('throws when used together with `entryTypes`', () => { const observer = new PerformanceObserver(() => {}); diff --git a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js index 442f6a736113..24c9e1bc9be5 100644 --- a/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js +++ b/packages/rn-tester/js/examples/Performance/PerformanceApiExample.js @@ -143,7 +143,7 @@ function PerformanceObserverEventTimingExample(): React.Node { setEntries(newEntries); }); - observer.observe({type: 'event'}); + observer.observe({type: 'event', durationThreshold: 0}); return () => observer.disconnect(); }, []);