@@ -11,6 +11,8 @@ const {
1111 ArrayPrototypeSort,
1212 ArrayPrototypeConcat,
1313 Error,
14+ MathMax,
15+ MathMin,
1416 ObjectDefineProperties,
1517 ObjectFreeze,
1618 ObjectKeys,
@@ -95,11 +97,17 @@ const kSupportedEntryTypes = ObjectFreeze([
9597let markEntryBuffer = [ ] ;
9698let measureEntryBuffer = [ ] ;
9799let 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+
99108const kClearPerformanceEntryBuffers = ObjectFreeze ( {
100109 'mark' : 'performance.clearMarks' ,
101110 'measure' : 'performance.clearMeasures' ,
102- 'resource' : 'performance.clearResourceTimings' ,
103111} ) ;
104112const kWarnedEntryTypes = new SafeMap ( ) ;
105113
@@ -332,30 +340,38 @@ class PerformanceObserver {
332340 }
333341}
334342
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+ */
335348function enqueue ( entry ) {
336349 if ( ! isPerformanceEntry ( entry ) )
337350 throw new ERR_INVALID_ARG_TYPE ( 'entry' , 'PerformanceEntry' , entry ) ;
338351
339352 for ( const obs of kObservers ) {
340353 obs [ kMaybeBuffer ] ( entry ) ;
341354 }
355+ }
342356
357+ /**
358+ * Add the user timing entry to the global buffer.
359+ */
360+ function bufferUserTiming ( entry ) {
343361 const entryType = entry . entryType ;
344362 let buffer ;
345363 if ( entryType === 'mark' ) {
346364 buffer = markEntryBuffer ;
347365 } else if ( entryType === 'measure' ) {
348366 buffer = measureEntryBuffer ;
349- } else if ( entryType === 'resource' ) {
350- buffer = resourceTimingBuffer ;
351367 } else {
352368 return ;
353369 }
354370
355371 ArrayPrototypePush ( buffer , entry ) ;
356372 const count = buffer . length ;
357373
358- if ( count > kMaxPerformanceEntryBuffers &&
374+ if ( count > kPerformanceEntryBufferWarnSize &&
359375 ! kWarnedEntryTypes . has ( entryType ) ) {
360376 kWarnedEntryTypes . set ( entryType , true ) ;
361377 // No error code for this since it is a Warning
@@ -372,6 +388,59 @@ function enqueue(entry) {
372388 }
373389}
374390
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+
375444function clearEntriesFromBuffer ( type , name ) {
376445 if ( type !== 'mark' && type !== 'measure' && type !== 'resource' ) {
377446 return ;
@@ -492,4 +561,9 @@ module.exports = {
492561 filterBufferMapByNameAndType,
493562 startPerf,
494563 stopPerf,
564+
565+ bufferUserTiming,
566+ bufferResourceTiming,
567+ setResourceTimingBufferSize,
568+ setDispatchBufferFull,
495569} ;
0 commit comments