From cb6b754a4d4336e4dff1c95a9837acda798aa345 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 10:36:10 -0400 Subject: [PATCH 01/11] fix: Try to use a better performance API - Trying to address the inconsistencies between browsers - Always try to use the timeOrigin first, as long as its consistent with either the navigationStart or the current time - Otherwise, use the navigationStart if its consistent with the current time - And still fallback to date if all else fails --- packages/utils/src/time.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 83920c2417c6..f5a978905790 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -135,7 +135,14 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { if (!performance) { return undefined; } - if (performance.timeOrigin) { + // If performance APIs are over an hour skewed don't use them + const THRESHOLD = 3600 * 1000; + // eslint-disable-next-line deprecation/deprecation + const performanceTiming = performance.timing && performance.timing.navigationStart; + if (performance.timeOrigin && ( + Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || + performanceTiming && Math.abs(performance.timeOrigin - performanceTiming) < THRESHOLD + )) { return performance.timeOrigin; } // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin @@ -143,6 +150,11 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. - // eslint-disable-next-line deprecation/deprecation - return (performance.timing && performance.timing.navigationStart) || Date.now(); + if (performanceTiming && + Math.abs(performanceTiming + performance.now() - Date.now()) < THRESHOLD + ) { + return performanceTiming; + } + // Both performance functions are skewed, fallback to Date + return Date.now(); })(); From 19bee987a96ccb620aca8acaab5e7e137d3ddecf Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 12:01:32 -0400 Subject: [PATCH 02/11] lint --- packages/utils/src/time.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index f5a978905790..37657963a566 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -139,10 +139,11 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { const THRESHOLD = 3600 * 1000; // eslint-disable-next-line deprecation/deprecation const performanceTiming = performance.timing && performance.timing.navigationStart; - if (performance.timeOrigin && ( - Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || - performanceTiming && Math.abs(performance.timeOrigin - performanceTiming) < THRESHOLD - )) { + if ( + performance.timeOrigin && + (Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || + (performanceTiming && Math.abs(performance.timeOrigin - performanceTiming) < THRESHOLD)) + ) { return performance.timeOrigin; } // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin @@ -150,9 +151,7 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. - if (performanceTiming && - Math.abs(performanceTiming + performance.now() - Date.now()) < THRESHOLD - ) { + if (performanceTiming && Math.abs(performanceTiming + performance.now() - Date.now()) < THRESHOLD) { return performanceTiming; } // Both performance functions are skewed, fallback to Date From ecd3d2a65f5ae81f9907e845be0b4c986ee77954 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 12:23:11 -0400 Subject: [PATCH 03/11] ref: Addressing comments --- packages/utils/src/time.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 37657963a566..08da4ed76338 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -138,12 +138,14 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // If performance APIs are over an hour skewed don't use them const THRESHOLD = 3600 * 1000; // eslint-disable-next-line deprecation/deprecation - const performanceTiming = performance.timing && performance.timing.navigationStart; - if ( - performance.timeOrigin && - (Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || - (performanceTiming && Math.abs(performance.timeOrigin - performanceTiming) < THRESHOLD)) - ) { + const navigationStart = performance.timing && performance.timing.navigationStart; + // Unfortunately browsers may report an inaccurate timeOrigin, which results in poor results in performance data. We + // treat timeOrigin as reliable if they are within a reasonable threshold of the current time, or if both + // performance APIs are consistent with each other + const timeOriginIsReliable = + Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || + (navigationStart && Math.abs(performance.timeOrigin - navigationStart) < THRESHOLD); + if (performance.timeOrigin && timeOriginIsReliable) { return performance.timeOrigin; } // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin @@ -151,8 +153,8 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. - if (performanceTiming && Math.abs(performanceTiming + performance.now() - Date.now()) < THRESHOLD) { - return performanceTiming; + if (navigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD) { + return navigationStart; } // Both performance functions are skewed, fallback to Date return Date.now(); From cb5afad82769859d7342fa2f5e2b2601e110a92f Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 12:40:22 -0400 Subject: [PATCH 04/11] ref: Addressing comments v2 --- packages/utils/src/time.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 08da4ed76338..cb648ef2b480 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -139,12 +139,15 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { const THRESHOLD = 3600 * 1000; // eslint-disable-next-line deprecation/deprecation const navigationStart = performance.timing && performance.timing.navigationStart; - // Unfortunately browsers may report an inaccurate timeOrigin, which results in poor results in performance data. We - // treat timeOrigin as reliable if they are within a reasonable threshold of the current time, or if both - // performance APIs are consistent with each other - const timeOriginIsReliable = - Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD || - (navigationStart && Math.abs(performance.timeOrigin - navigationStart) < THRESHOLD); + const hasNavigationStart = typeof navigationStart === 'number'; + // Unfortunately browsers may report an inaccurate time origin data, which results in poor results in performance + // data. We treat time origin data as reliable if they are either within a reasonable threshold of the current time, + // or if both timeOrigin and navigationStart are within the same threshold + + const timeOriginIsReliableWithDate = Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; + const timeOriginIsReliableWithNavigation = + hasNavigationStart && Math.abs(performance.timeOrigin - navigationStart) < THRESHOLD; + const timeOriginIsReliable = timeOriginIsReliableWithDate || timeOriginIsReliableWithNavigation; if (performance.timeOrigin && timeOriginIsReliable) { return performance.timeOrigin; } @@ -153,7 +156,8 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. - if (navigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD) { + const navigationStartIsReliable = Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD; + if (hasNavigationStart && navigationStartIsReliable) { return navigationStart; } // Both performance functions are skewed, fallback to Date From a063aa2f5f57d0d171c90a05c7dce93ca1a479c1 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 13:01:56 -0400 Subject: [PATCH 05/11] ref: Removing unneccesary condition --- packages/utils/src/time.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index cb648ef2b480..2365b24819f0 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -142,12 +142,8 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { const hasNavigationStart = typeof navigationStart === 'number'; // Unfortunately browsers may report an inaccurate time origin data, which results in poor results in performance // data. We treat time origin data as reliable if they are either within a reasonable threshold of the current time, - // or if both timeOrigin and navigationStart are within the same threshold - const timeOriginIsReliableWithDate = Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; - const timeOriginIsReliableWithNavigation = - hasNavigationStart && Math.abs(performance.timeOrigin - navigationStart) < THRESHOLD; - const timeOriginIsReliable = timeOriginIsReliableWithDate || timeOriginIsReliableWithNavigation; + const timeOriginIsReliable = Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; if (performance.timeOrigin && timeOriginIsReliable) { return performance.timeOrigin; } From c8576bdb1c596ceccf1f8ca6bbeda3fcbfd3e306 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 13:03:55 -0400 Subject: [PATCH 06/11] Update packages/utils/src/time.ts Co-authored-by: Rodolfo Carvalho --- packages/utils/src/time.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 2365b24819f0..9250f304b640 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -156,6 +156,6 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { if (hasNavigationStart && navigationStartIsReliable) { return navigationStart; } - // Both performance functions are skewed, fallback to Date + // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date. return Date.now(); })(); From 43bf5aa4802e3513d163b9c9599faf541e406b16 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 13:09:00 -0400 Subject: [PATCH 07/11] Update packages/utils/src/time.ts Co-authored-by: Rodolfo Carvalho --- packages/utils/src/time.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 9250f304b640..75049c484f13 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -143,7 +143,7 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Unfortunately browsers may report an inaccurate time origin data, which results in poor results in performance // data. We treat time origin data as reliable if they are either within a reasonable threshold of the current time, - const timeOriginIsReliable = Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; + const timeOriginIsReliable = performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; if (performance.timeOrigin && timeOriginIsReliable) { return performance.timeOrigin; } From 00821087b9ceac4ddd7dcf5caf42b80f06b76587 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 13:23:03 -0400 Subject: [PATCH 08/11] ref: Fixing comment, moving some code around --- packages/utils/src/time.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 2365b24819f0..1f0c8bc106a6 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -137,11 +137,9 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { } // If performance APIs are over an hour skewed don't use them const THRESHOLD = 3600 * 1000; - // eslint-disable-next-line deprecation/deprecation - const navigationStart = performance.timing && performance.timing.navigationStart; - const hasNavigationStart = typeof navigationStart === 'number'; - // Unfortunately browsers may report an inaccurate time origin data, which results in poor results in performance - // data. We treat time origin data as reliable if they are either within a reasonable threshold of the current time, + // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or + // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin + // data as reliable if they are within a reasonable threshold of the current time. const timeOriginIsReliable = Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; if (performance.timeOrigin && timeOriginIsReliable) { @@ -152,6 +150,9 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. + // eslint-disable-next-line deprecation/deprecation + const navigationStart = performance.timing && performance.timing.navigationStart; + const hasNavigationStart = typeof navigationStart === 'number'; const navigationStartIsReliable = Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD; if (hasNavigationStart && navigationStartIsReliable) { return navigationStart; From 7506fbc2159ae61d5a9b232be2d9c71327bb4f34 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 13:41:20 -0400 Subject: [PATCH 09/11] ref: Moving some variables --- packages/utils/src/time.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index b80ba989bc2d..bd09bb9ebdf2 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -141,7 +141,8 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin // data as reliable if they are within a reasonable threshold of the current time. - const timeOriginIsReliable = performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; + const timeOriginIsReliable = + performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; if (performance.timeOrigin && timeOriginIsReliable) { return performance.timeOrigin; } @@ -153,8 +154,9 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { // eslint-disable-next-line deprecation/deprecation const navigationStart = performance.timing && performance.timing.navigationStart; const hasNavigationStart = typeof navigationStart === 'number'; - const navigationStartIsReliable = Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD; - if (hasNavigationStart && navigationStartIsReliable) { + const navigationStartIsReliable = + hasNavigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD; + if (navigationStartIsReliable) { return navigationStart; } // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date. From c5bed0bb6f34eaca7bceeaa9adf6f82e8a65f941 Mon Sep 17 00:00:00 2001 From: William Mak Date: Tue, 30 Mar 2021 21:49:14 -0400 Subject: [PATCH 10/11] Update packages/utils/src/time.ts Co-authored-by: Alberto Leal --- packages/utils/src/time.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index bd09bb9ebdf2..4075276be883 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -143,7 +143,7 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { const timeOriginIsReliable = performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; - if (performance.timeOrigin && timeOriginIsReliable) { + if (timeOriginIsReliable) { return performance.timeOrigin; } // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin From e856e40b6e71a73252e788cd42b5260f81c9c88e Mon Sep 17 00:00:00 2001 From: Rodolfo Carvalho Date: Wed, 31 Mar 2021 18:56:43 +0200 Subject: [PATCH 11/11] debug: Remember how Performance Time Origin was set --- packages/utils/src/time.ts | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/utils/src/time.ts b/packages/utils/src/time.ts index 4075276be883..91d6ed92fc55 100644 --- a/packages/utils/src/time.ts +++ b/packages/utils/src/time.ts @@ -126,26 +126,35 @@ export const timestampWithMs = timestampInSeconds; */ export const usingPerformanceAPI = platformPerformance !== undefined; +/** + * Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only. + */ +export let _browserPerformanceTimeOriginMode: string; + /** * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the * performance API is available. */ export const browserPerformanceTimeOrigin = ((): number | undefined => { + // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or + // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin + // data as reliable if they are within a reasonable threshold of the current time. + const { performance } = getGlobalObject(); if (!performance) { + _browserPerformanceTimeOriginMode = 'none'; return undefined; } - // If performance APIs are over an hour skewed don't use them - const THRESHOLD = 3600 * 1000; - // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or - // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin - // data as reliable if they are within a reasonable threshold of the current time. + + const threshold = 3600 * 1000; const timeOriginIsReliable = - performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < THRESHOLD; + performance.timeOrigin && Math.abs(performance.timeOrigin + performance.now() - Date.now()) < threshold; if (timeOriginIsReliable) { + _browserPerformanceTimeOriginMode = 'timeOrigin'; return performance.timeOrigin; } + // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing. // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always @@ -155,10 +164,13 @@ export const browserPerformanceTimeOrigin = ((): number | undefined => { const navigationStart = performance.timing && performance.timing.navigationStart; const hasNavigationStart = typeof navigationStart === 'number'; const navigationStartIsReliable = - hasNavigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < THRESHOLD; + hasNavigationStart && Math.abs(navigationStart + performance.now() - Date.now()) < threshold; if (navigationStartIsReliable) { + _browserPerformanceTimeOriginMode = 'navigationStart'; return navigationStart; } + // Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date. + _browserPerformanceTimeOriginMode = 'dateNow'; return Date.now(); })();