diff --git a/packages/react-native/Libraries/Network/XMLHttpRequest.js b/packages/react-native/Libraries/Network/XMLHttpRequest.js index 458f0780a0f..7697233ae0a 100644 --- a/packages/react-native/Libraries/Network/XMLHttpRequest.js +++ b/packages/react-native/Libraries/Network/XMLHttpRequest.js @@ -22,6 +22,7 @@ const base64 = require('base64-js'); const invariant = require('invariant'); const DEBUG_NETWORK_SEND_DELAY: false = false; // Set to a number of milliseconds when debugging +const LABEL_FOR_MISSING_URL_FOR_PROFILING = 'Unknown URL'; export type NativeResponseType = 'base64' | 'blob' | 'text'; export type ResponseType = @@ -101,6 +102,7 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { static DONE: number = DONE; static _interceptor: ?XHRInterceptor = null; + static _profiling: boolean = false; UNSENT: number = UNSENT; OPENED: number = OPENED; @@ -144,12 +146,17 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { _timedOut: boolean = false; _trackingName: string = 'unknown'; _incrementalEvents: boolean = false; + _startTime: ?number = null; _performanceLogger: IPerformanceLogger = GlobalPerformanceLogger; static setInterceptor(interceptor: ?XHRInterceptor) { XMLHttpRequest._interceptor = interceptor; } + static enableProfiling(enableProfiling: boolean): void { + XMLHttpRequest._profiling = enableProfiling; + } + constructor() { super(); this._reset(); @@ -356,6 +363,11 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { this._response += responseText; } + if (XMLHttpRequest._profiling) { + performance.mark( + 'Track:XMLHttpRequest:Incremental Data: ' + this._getMeasureURL(), + ); + } XMLHttpRequest._interceptor && XMLHttpRequest._interceptor.dataReceived(requestId, responseText); @@ -398,7 +410,13 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { this._clearSubscriptions(); this._requestId = null; this.setReadyState(this.DONE); - + if (XMLHttpRequest._profiling && this._startTime != null) { + const start = this._startTime; + performance.measure('Track:XMLHttpRequest:' + this._getMeasureURL(), { + start, + end: performance.now(), + }); + } if (error) { XMLHttpRequest._interceptor && XMLHttpRequest._interceptor.loadingFailed(requestId, error); @@ -572,6 +590,7 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { this._trackingName !== 'unknown' ? this._trackingName : this._url; this._perfKey = 'network_XMLHttpRequest_' + String(friendlyName); this._performanceLogger.startTimespan(this._perfKey); + this._startTime = performance.now(); invariant( this._method, 'XMLHttpRequest method needs to be defined (%s).', @@ -668,6 +687,12 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { } super.addEventListener(type, listener); } + + _getMeasureURL(): string { + return ( + this._trackingName ?? this._url ?? LABEL_FOR_MISSING_URL_FOR_PROFILING + ); + } } module.exports = XMLHttpRequest; diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 15cd6c00cce..ae2abed6d49 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -6750,6 +6750,7 @@ declare class XMLHttpRequest extends EventTarget { static LOADING: number; static DONE: number; static _interceptor: ?XHRInterceptor; + static _profiling: boolean; UNSENT: number; OPENED: number; HEADERS_RECEIVED: number; @@ -6786,8 +6787,10 @@ declare class XMLHttpRequest extends EventTarget { _timedOut: boolean; _trackingName: string; _incrementalEvents: boolean; + _startTime: ?number; _performanceLogger: IPerformanceLogger; static setInterceptor(interceptor: ?XHRInterceptor): void; + static enableProfiling(enableProfiling: boolean): void; constructor(): void; _reset(): void; get responseType(): ResponseType; @@ -6831,6 +6834,7 @@ declare class XMLHttpRequest extends EventTarget { setResponseHeaders(responseHeaders: ?Object): void; setReadyState(newState: number): void; addEventListener(type: string, listener: EventListener): void; + _getMeasureURL(): string; } declare module.exports: XMLHttpRequest; "