@@ -11,6 +11,8 @@ const {
11
11
ArrayPrototypeSort,
12
12
ArrayPrototypeConcat,
13
13
Error,
14
+ MathMax,
15
+ MathMin,
14
16
ObjectDefineProperties,
15
17
ObjectFreeze,
16
18
ObjectKeys,
@@ -95,11 +97,17 @@ const kSupportedEntryTypes = ObjectFreeze([
95
97
let markEntryBuffer = [ ] ;
96
98
let measureEntryBuffer = [ ] ;
97
99
let resourceTimingBuffer = [ ] ;
98
- const kMaxPerformanceEntryBuffers = 1e6 ;
100
+ let resourceTimingSecondaryBuffer = [ ] ;
101
+ const kPerformanceEntryBufferWarnSize = 1e6 ;
102
+ // https://www.w3.org/TR/timing-entrytypes-registry/#registry
103
+ // Default buffer limit for resource timing entries.
104
+ let resourceTimingBufferSizeLimit = 250 ;
105
+ let dispatchBufferFull ;
106
+ let resourceTimingBufferFullPending = false ;
107
+
99
108
const kClearPerformanceEntryBuffers = ObjectFreeze ( {
100
109
'mark' : 'performance.clearMarks' ,
101
110
'measure' : 'performance.clearMeasures' ,
102
- 'resource' : 'performance.clearResourceTimings' ,
103
111
} ) ;
104
112
const kWarnedEntryTypes = new SafeMap ( ) ;
105
113
@@ -332,30 +340,38 @@ class PerformanceObserver {
332
340
}
333
341
}
334
342
343
+ /**
344
+ * https://www.w3.org/TR/performance-timeline/#dfn-queue-a-performanceentry
345
+ *
346
+ * Add the performance entry to the interested performance observer's queue.
347
+ */
335
348
function enqueue ( entry ) {
336
349
if ( ! isPerformanceEntry ( entry ) )
337
350
throw new ERR_INVALID_ARG_TYPE ( 'entry' , 'PerformanceEntry' , entry ) ;
338
351
339
352
for ( const obs of kObservers ) {
340
353
obs [ kMaybeBuffer ] ( entry ) ;
341
354
}
355
+ }
342
356
357
+ /**
358
+ * Add the user timing entry to the global buffer.
359
+ */
360
+ function bufferUserTiming ( entry ) {
343
361
const entryType = entry . entryType ;
344
362
let buffer ;
345
363
if ( entryType === 'mark' ) {
346
364
buffer = markEntryBuffer ;
347
365
} else if ( entryType === 'measure' ) {
348
366
buffer = measureEntryBuffer ;
349
- } else if ( entryType === 'resource' ) {
350
- buffer = resourceTimingBuffer ;
351
367
} else {
352
368
return ;
353
369
}
354
370
355
371
ArrayPrototypePush ( buffer , entry ) ;
356
372
const count = buffer . length ;
357
373
358
- if ( count > kMaxPerformanceEntryBuffers &&
374
+ if ( count > kPerformanceEntryBufferWarnSize &&
359
375
! kWarnedEntryTypes . has ( entryType ) ) {
360
376
kWarnedEntryTypes . set ( entryType , true ) ;
361
377
// No error code for this since it is a Warning
@@ -372,6 +388,59 @@ function enqueue(entry) {
372
388
}
373
389
}
374
390
391
+ /**
392
+ * Add the resource timing entry to the global buffer if the buffer size is not
393
+ * exceeding the buffer limit, or dispatch a buffer full event on the global
394
+ * performance object.
395
+ *
396
+ * See also https://www.w3.org/TR/resource-timing-2/#dfn-add-a-performanceresourcetiming-entry
397
+ */
398
+ function bufferResourceTiming ( entry ) {
399
+ if ( resourceTimingBuffer . length < resourceTimingBufferSizeLimit && ! resourceTimingBufferFullPending ) {
400
+ ArrayPrototypePush ( resourceTimingBuffer , entry ) ;
401
+ return ;
402
+ }
403
+
404
+ if ( ! resourceTimingBufferFullPending ) {
405
+ resourceTimingBufferFullPending = true ;
406
+ setImmediate ( ( ) => {
407
+ while ( resourceTimingSecondaryBuffer . length > 0 ) {
408
+ const excessNumberBefore = resourceTimingSecondaryBuffer . length ;
409
+ dispatchBufferFull ( 'resourcetimingbufferfull' ) ;
410
+
411
+ // Calculate the number of items to be pushed to the global buffer.
412
+ const numbersToPreserve = MathMax (
413
+ MathMin ( resourceTimingBufferSizeLimit - resourceTimingBuffer . length , resourceTimingSecondaryBuffer . length ) ,
414
+ 0
415
+ ) ;
416
+ const excessNumberAfter = resourceTimingSecondaryBuffer . length - numbersToPreserve ;
417
+ for ( let idx = 0 ; idx < numbersToPreserve ; idx ++ ) {
418
+ ArrayPrototypePush ( resourceTimingBuffer , resourceTimingSecondaryBuffer [ idx ] ) ;
419
+ }
420
+
421
+ if ( excessNumberBefore <= excessNumberAfter ) {
422
+ resourceTimingSecondaryBuffer = [ ] ;
423
+ }
424
+ }
425
+ resourceTimingBufferFullPending = false ;
426
+ } ) ;
427
+ }
428
+
429
+ ArrayPrototypePush ( resourceTimingSecondaryBuffer , entry ) ;
430
+ }
431
+
432
+ // https://w3c.github.io/resource-timing/#dom-performance-setresourcetimingbuffersize
433
+ function setResourceTimingBufferSize ( maxSize ) {
434
+ // If the maxSize parameter is less than resource timing buffer current
435
+ // size, no PerformanceResourceTiming objects are to be removed from the
436
+ // performance entry buffer.
437
+ resourceTimingBufferSizeLimit = maxSize ;
438
+ }
439
+
440
+ function setDispatchBufferFull ( fn ) {
441
+ dispatchBufferFull = fn ;
442
+ }
443
+
375
444
function clearEntriesFromBuffer ( type , name ) {
376
445
if ( type !== 'mark' && type !== 'measure' && type !== 'resource' ) {
377
446
return ;
@@ -492,4 +561,9 @@ module.exports = {
492
561
filterBufferMapByNameAndType,
493
562
startPerf,
494
563
stopPerf,
564
+
565
+ bufferUserTiming,
566
+ bufferResourceTiming,
567
+ setResourceTimingBufferSize,
568
+ setDispatchBufferFull,
495
569
} ;
0 commit comments