@@ -142,18 +142,38 @@ function initPerformanceObserver(
142
142
} ;
143
143
}
144
144
145
- const getPerformanceEntryByUrl = (
145
+ const getRequestPerformanceEntry = async (
146
146
win : IWindow ,
147
147
initiatorType : string ,
148
148
url : string ,
149
- ) => {
149
+ after ?: number ,
150
+ before ?: number ,
151
+ attempt = 0 ,
152
+ ) : Promise < PerformanceEntry > => {
153
+ if ( attempt > 10 ) {
154
+ throw new Error ( 'Cannot find performance entry' ) ;
155
+ }
150
156
const urlPerformanceEntries = win . performance . getEntriesByName ( url ) ;
151
- return findLast (
157
+ const performanceEntry = findLast (
152
158
urlPerformanceEntries ,
153
159
( performanceEntry ) =>
154
160
isResourceTiming ( performanceEntry ) &&
155
- performanceEntry . initiatorType === initiatorType ,
161
+ performanceEntry . initiatorType === initiatorType &&
162
+ ( ! after || performanceEntry . startTime >= after ) &&
163
+ ( ! before || performanceEntry . startTime <= before ) ,
156
164
) ;
165
+ if ( ! performanceEntry ) {
166
+ await new Promise ( ( resolve ) => setTimeout ( resolve , 50 * attempt ) ) ;
167
+ return getRequestPerformanceEntry (
168
+ win ,
169
+ initiatorType ,
170
+ url ,
171
+ after ,
172
+ before ,
173
+ attempt + 1 ,
174
+ ) ;
175
+ }
176
+ return performanceEntry ;
157
177
} ;
158
178
159
179
function initXhrObserver (
@@ -191,7 +211,7 @@ function initXhrObserver(
191
211
XMLHttpRequest . prototype ,
192
212
'open' ,
193
213
( originalOpen : typeof XMLHttpRequest . prototype . open ) => {
194
- return async function (
214
+ return function (
195
215
method : string ,
196
216
url : string | URL ,
197
217
async = true ,
@@ -200,8 +220,9 @@ function initXhrObserver(
200
220
) {
201
221
const xhr = this as XMLHttpRequest ;
202
222
const req = new Request ( url ) ;
203
- let performanceEntry : PerformanceEntry | undefined ;
204
223
const networkRequest : Partial < NetworkRequest > = { } ;
224
+ let after : number | undefined ;
225
+ let before : number | undefined ;
205
226
if ( recordRequestHeaders ) {
206
227
networkRequest . requestHeaders = { } ;
207
228
const originalSetRequestHeader = xhr . setRequestHeader . bind ( xhr ) ;
@@ -210,9 +231,9 @@ function initXhrObserver(
210
231
return originalSetRequestHeader ( header , value ) ;
211
232
} ;
212
233
}
213
- if ( recordRequestBody ) {
214
- const originalSend = xhr . send . bind ( xhr ) ;
215
- xhr . send = ( body ) => {
234
+ const originalSend = xhr . send . bind ( xhr ) ;
235
+ xhr . send = ( body ) => {
236
+ if ( recordRequestBody ) {
216
237
if ( body === undefined || body === null ) {
217
238
networkRequest . requestBody = null ;
218
239
} else {
@@ -223,64 +244,65 @@ function initXhrObserver(
223
244
: undefined ,
224
245
) ;
225
246
}
226
- return originalSend ( body ) ;
227
- } ;
228
- }
229
- await new Promise < void > ( ( resolve ) => {
230
- xhr . addEventListener ( 'readystatechange' , ( ) => {
231
- if ( xhr . readyState !== xhr . DONE ) {
232
- return ;
233
- }
234
- performanceEntry = getPerformanceEntryByUrl (
235
- win ,
236
- 'xmlhttprequest' ,
237
- req . url ,
238
- ) ;
239
- if ( recordResponseHeaders ) {
240
- networkRequest . responseHeaders = { } ;
241
- const rawHeaders = xhr . getAllResponseHeaders ( ) ;
242
- const headers = rawHeaders . trim ( ) . split ( / [ \r \n ] + / ) ;
243
- headers . forEach ( ( line ) => {
244
- const parts = line . split ( ': ' ) ;
245
- const header = parts . shift ( ) ;
246
- const value = parts . join ( ': ' ) ;
247
- if ( header ) {
248
- networkRequest . responseHeaders ! [ header ] = value ;
249
- }
250
- } ) ;
251
- }
252
- if ( recordResponseBody ) {
253
- if ( ! xhr . response ) {
254
- networkRequest . responseBody = null ;
255
- } else {
256
- try {
257
- const objBody = JSON . parse ( xhr . response as string ) as object ;
258
- networkRequest . responseBody = stringify (
259
- objBody ,
260
- typeof recordResponseBody === 'object'
261
- ? recordResponseBody
262
- : undefined ,
263
- ) ;
264
- } catch {
265
- networkRequest . responseBody = xhr . response as string ;
266
- }
247
+ }
248
+ after = win . performance . now ( ) ;
249
+ return originalSend ( body ) ;
250
+ } ;
251
+ xhr . addEventListener ( 'readystatechange' , ( ) => {
252
+ if ( xhr . readyState !== xhr . DONE ) {
253
+ return ;
254
+ }
255
+ before = win . performance . now ( ) ;
256
+ if ( recordResponseHeaders ) {
257
+ networkRequest . responseHeaders = { } ;
258
+ const rawHeaders = xhr . getAllResponseHeaders ( ) ;
259
+ const headers = rawHeaders . trim ( ) . split ( / [ \r \n ] + / ) ;
260
+ headers . forEach ( ( line ) => {
261
+ const parts = line . split ( ': ' ) ;
262
+ const header = parts . shift ( ) ;
263
+ const value = parts . join ( ': ' ) ;
264
+ if ( header ) {
265
+ networkRequest . responseHeaders ! [ header ] = value ;
266
+ }
267
+ } ) ;
268
+ }
269
+ if ( recordResponseBody ) {
270
+ if ( ! xhr . response ) {
271
+ networkRequest . responseBody = null ;
272
+ } else {
273
+ try {
274
+ const objBody = JSON . parse ( xhr . response as string ) as object ;
275
+ networkRequest . responseBody = stringify (
276
+ objBody ,
277
+ typeof recordResponseBody === 'object'
278
+ ? recordResponseBody
279
+ : undefined ,
280
+ ) ;
281
+ } catch {
282
+ networkRequest . responseBody = xhr . response as string ;
267
283
}
268
284
}
269
- resolve ( ) ;
270
- } ) ;
271
- originalOpen ( method , url , async , username , password ) ;
272
- } ) ;
273
- if ( performanceEntry ) {
274
- cb ( {
275
- requests : [
276
- {
285
+ }
286
+ getRequestPerformanceEntry (
287
+ win ,
288
+ 'xmlhttprequest' ,
289
+ req . url ,
290
+ after ,
291
+ before ,
292
+ )
293
+ . then ( ( performanceEntry ) => {
294
+ const request : NetworkRequest = {
277
295
performanceEntry,
278
296
requestMethod : req . method ,
279
297
...networkRequest ,
280
- } ,
281
- ] ,
282
- } ) ;
283
- }
298
+ } ;
299
+ cb ( { requests : [ request ] } ) ;
300
+ } )
301
+ . catch ( ( ) => {
302
+ //
303
+ } ) ;
304
+ } ) ;
305
+ originalOpen ( method , url , async , username , password ) ;
284
306
} ;
285
307
} ,
286
308
) ;
@@ -323,8 +345,9 @@ function initFetchObserver(
323
345
const originalFetch = win . fetch ;
324
346
const wrappedFetch : typeof fetch = async ( url , init ) => {
325
347
const req = new Request ( url , init ) ;
326
- let performanceEntry : PerformanceEntry | undefined ;
327
348
const networkRequest : Partial < NetworkRequest > = { } ;
349
+ let after : number | undefined ;
350
+ let before : number | undefined ;
328
351
try {
329
352
if ( recordRequestHeaders ) {
330
353
networkRequest . requestHeaders = { } ;
@@ -344,8 +367,9 @@ function initFetchObserver(
344
367
) ;
345
368
}
346
369
}
370
+ after = win . performance . now ( ) ;
347
371
const res = await originalFetch ( req ) ;
348
- performanceEntry = getPerformanceEntryByUrl ( win , 'fetch' , req . url ) ;
372
+ before = win . performance . now ( ) ;
349
373
if ( recordResponseHeaders ) {
350
374
networkRequest . responseHeaders = { } ;
351
375
res . headers . forEach ( ( value , header ) => {
@@ -371,23 +395,19 @@ function initFetchObserver(
371
395
}
372
396
}
373
397
return res ;
374
- } catch ( cause ) {
375
- if ( ! performanceEntry ) {
376
- performanceEntry = getPerformanceEntryByUrl ( win , 'fetch' , req . url ) ;
377
- }
378
- throw cause ;
379
398
} finally {
380
- if ( performanceEntry ) {
381
- cb ( {
382
- requests : [
383
- {
384
- performanceEntry,
385
- requestMethod : req . method ,
386
- ...networkRequest ,
387
- } ,
388
- ] ,
399
+ getRequestPerformanceEntry ( win , 'fetch' , req . url , after , before )
400
+ . then ( ( performanceEntry ) => {
401
+ const request : NetworkRequest = {
402
+ performanceEntry,
403
+ requestMethod : req . method ,
404
+ ...networkRequest ,
405
+ } ;
406
+ cb ( { requests : [ request ] } ) ;
407
+ } )
408
+ . catch ( ( ) => {
409
+ //
389
410
} ) ;
390
- }
391
411
}
392
412
} ;
393
413
wrappedFetch . prototype = { } ;
0 commit comments