From dfbb63996a53c6ced9680cc650d6f9eeca863bfe Mon Sep 17 00:00:00 2001 From: Ruslan Shestopalyuk Date: Fri, 2 Dec 2022 11:17:27 -0800 Subject: [PATCH] Don't use public fields in PerformanceObserver API Summary: [Changelog][Internal] A follow up to the [discussion](https://www.internalfb.com/diff/D41496082 (https://github.com/facebook/react-native/commit/14e69db4826c2a14f3bc7bcd3a81fc56644b4f9b)?dst_version_fbid=831443041436872&transaction_fbid=1281583632681733) in D41496082 (https://github.com/facebook/react-native/commit/14e69db4826c2a14f3bc7bcd3a81fc56644b4f9b), this gets rid of the non-private fields in the `PerformanceObserver` - both to prevent abuse and better conform to the standard. Reviewed By: rubennorte Differential Revision: D41683363 fbshipit-source-id: 1fc98ff77e0bcdbf66c2a768e8b27a726831f106 --- .../WebPerformance/PerformanceObserver.js | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/Libraries/WebPerformance/PerformanceObserver.js b/Libraries/WebPerformance/PerformanceObserver.js index 477e03a2e67..6c6566173db 100644 --- a/Libraries/WebPerformance/PerformanceObserver.js +++ b/Libraries/WebPerformance/PerformanceObserver.js @@ -110,7 +110,12 @@ export type PerformanceObserverInit = const _observedEntryTypeRefCount: Map = new Map(); -const _observers: Set = new Set(); +type PerformanceObserverData = {| + callback: PerformanceObserverCallback, + entryTypes: $ReadOnlySet, +|}; + +const _observers: Map = new Map(); let _onPerformanceEntryCallbackIsSet: boolean = false; @@ -124,11 +129,11 @@ const onPerformanceEntry = () => { return; } const entries = rawEntries.map(rawToPerformanceEntry); - for (const observer of _observers) { + for (const [observer, observerData] of _observers.entries()) { const entriesForObserver: PerformanceEntryList = entries.filter( - entry => observer.entryTypes.has(entry.entryType) !== -1, + entry => observerData.entryTypes.has(entry.entryType) !== -1, ); - observer.callback( + observerData.callback( new PerformanceObserverEntryList(entriesForObserver), observer, ); @@ -163,11 +168,10 @@ function warnNoNativePerformanceObserver() { * observer.observe({ type: "event" }); */ export default class PerformanceObserver { - callback: PerformanceObserverCallback; - entryTypes: $ReadOnlySet; + _callback: PerformanceObserverCallback; constructor(callback: PerformanceObserverCallback) { - this.callback = callback; + this._callback = callback; } observe(options: PerformanceObserverInit) { @@ -183,12 +187,10 @@ export default class PerformanceObserver { _onPerformanceEntryCallbackIsSet = true; } - if (options.entryTypes) { - this.entryTypes = new Set(options.entryTypes); - } else { - this.entryTypes = new Set([options.type]); - } - for (const type of this.entryTypes) { + let entryTypes = options.entryTypes + ? new Set(options.entryTypes) + : new Set([options.type]); + for (const type of entryTypes) { if (!_observedEntryTypeRefCount.has(type)) { NativePerformanceObserver.startReporting(type); } @@ -197,7 +199,9 @@ export default class PerformanceObserver { (_observedEntryTypeRefCount.get(type) ?? 0) + 1, ); } - _observers.add(this); + // TODO: Handle correctly the cases when "observe" is called multiple times + // on the same observer (potentially with different entry types) + _observers.set(this, {entryTypes, callback: this._callback}); } disconnect(): void { @@ -205,7 +209,8 @@ export default class PerformanceObserver { warnNoNativePerformanceObserver(); return; } - for (const type of this.entryTypes) { + const data = _observers.get(this); + for (const type of data?.entryTypes ?? []) { const entryTypeRefCount = _observedEntryTypeRefCount.get(type) ?? 0; if (entryTypeRefCount === 1) { _observedEntryTypeRefCount.delete(type);