@@ -11,10 +11,13 @@ import {
1111 addFidInstrumentationHandler ,
1212 addLcpInstrumentationHandler ,
1313 addPerformanceInstrumentationHandler ,
14+ addTtfbInstrumentationHandler ,
1415} from '../instrument' ;
1516import { WINDOW } from '../types' ;
17+ import { getNavigationEntry } from '../web-vitals/lib/getNavigationEntry' ;
1618import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher' ;
1719import type { NavigatorDeviceMemory , NavigatorNetworkInformation } from '../web-vitals/types' ;
20+ import type { TTFBMetric } from '../web-vitals/types/ttfb' ;
1821import { isMeasurementValue , startAndEndSpan } from './utils' ;
1922
2023const MAX_INT_AS_BYTES = 2147483647 ;
@@ -54,11 +57,13 @@ export function startTrackingWebVitals(): () => void {
5457 const fidCallback = _trackFID ( ) ;
5558 const clsCallback = _trackCLS ( ) ;
5659 const lcpCallback = _trackLCP ( ) ;
60+ const ttfbCallback = _trackTtfb ( ) ;
5761
5862 return ( ) : void => {
5963 fidCallback ( ) ;
6064 clsCallback ( ) ;
6165 lcpCallback ( ) ;
66+ ttfbCallback ( ) ;
6267 } ;
6368 }
6469
@@ -173,6 +178,18 @@ function _trackFID(): () => void {
173178 } ) ;
174179}
175180
181+ function _trackTtfb ( ) : ( ) => void {
182+ return addTtfbInstrumentationHandler ( ( { metric } ) => {
183+ const entry = metric . entries [ metric . entries . length - 1 ] ;
184+ if ( ! entry ) {
185+ return ;
186+ }
187+
188+ DEBUG_BUILD && logger . log ( '[Measurements] Adding TTFB' ) ;
189+ _measurements [ 'ttfb' ] = { value : metric . value , unit : 'millisecond' } ;
190+ } ) ;
191+ }
192+
176193/** Add performance related spans to a span */
177194export function addPerformanceEntries ( span : Span ) : void {
178195 const performance = getBrowserPerformanceAPI ( ) ;
@@ -186,9 +203,6 @@ export function addPerformanceEntries(span: Span): void {
186203
187204 const performanceEntries = performance . getEntries ( ) ;
188205
189- let responseStartTimestamp : number | undefined ;
190- let requestStartTimestamp : number | undefined ;
191-
192206 const { op, start_timestamp : transactionStartTime } = spanToJSON ( span ) ;
193207
194208 // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -203,8 +217,6 @@ export function addPerformanceEntries(span: Span): void {
203217 switch ( entry . entryType ) {
204218 case 'navigation' : {
205219 _addNavigationSpans ( span , entry , timeOrigin ) ;
206- responseStartTimestamp = timeOrigin + msToSec ( entry . responseStart ) ;
207- requestStartTimestamp = timeOrigin + msToSec ( entry . requestStart ) ;
208220 break ;
209221 }
210222 case 'mark' :
@@ -242,7 +254,7 @@ export function addPerformanceEntries(span: Span): void {
242254
243255 // Measurements are only available for pageload transactions
244256 if ( op === 'pageload' ) {
245- _addTtfbToMeasurements ( _measurements , responseStartTimestamp , requestStartTimestamp , transactionStartTime ) ;
257+ _addTtfbRequestTimeToMeasurements ( _measurements ) ;
246258
247259 [ 'fcp' , 'fp' , 'lcp' ] . forEach ( name => {
248260 if ( ! _measurements [ name ] || ! transactionStartTime || timeOrigin >= transactionStartTime ) {
@@ -528,35 +540,15 @@ function setResourceEntrySizeData(
528540 *
529541 * Exported for tests
530542 */
531- export function _addTtfbToMeasurements (
532- _measurements : Measurements ,
533- responseStartTimestamp : number | undefined ,
534- requestStartTimestamp : number | undefined ,
535- transactionStartTime : number | undefined ,
536- ) : void {
537- // Generate TTFB (Time to First Byte), which measured as the time between the beginning of the span and the
538- // start of the response in milliseconds
539- if ( typeof responseStartTimestamp === 'number' && transactionStartTime ) {
543+ export function _addTtfbRequestTimeToMeasurements ( _measurements : Measurements ) : void {
544+ const navEntry = getNavigationEntry ( ) as TTFBMetric [ 'entries' ] [ number ] ;
545+ const { responseStart, requestStart } = navEntry ;
546+
547+ if ( requestStart <= responseStart ) {
540548 DEBUG_BUILD && logger . log ( '[Measurements] Adding TTFB' ) ;
541- _measurements [ 'ttfb' ] = {
542- // As per https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming/responseStart,
543- // responseStart can be 0 if the request is coming straight from the cache.
544- // This might lead us to calculate a negative ttfb if we don't use Math.max here.
545- //
546- // This logic is the same as what is in the web-vitals library to calculate ttfb
547- // https://github.com/GoogleChrome/web-vitals/blob/2301de5015e82b09925238a228a0893635854587/src/onTTFB.ts#L92
548- // TODO(abhi): We should use the web-vitals library instead of this custom calculation.
549- value : Math . max ( responseStartTimestamp - transactionStartTime , 0 ) * 1000 ,
549+ _measurements [ 'ttfb.requestTime' ] = {
550+ value : ( responseStart - requestStart ) * 1000 ,
550551 unit : 'millisecond' ,
551552 } ;
552-
553- if ( typeof requestStartTimestamp === 'number' && requestStartTimestamp <= responseStartTimestamp ) {
554- // Capture the time spent making the request and receiving the first byte of the response.
555- // This is the time between the start of the request and the start of the response in milliseconds.
556- _measurements [ 'ttfb.requestTime' ] = {
557- value : ( responseStartTimestamp - requestStartTimestamp ) * 1000 ,
558- unit : 'millisecond' ,
559- } ;
560- }
561553 }
562554}
0 commit comments