Skip to content

fix: Try to use a better performance API #3356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Mar 31, 2021
32 changes: 30 additions & 2 deletions packages/utils/src/time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,23 +126,51 @@ 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<Window>();
if (!performance) {
_browserPerformanceTimeOriginMode = 'none';
return undefined;
}
if (performance.timeOrigin) {

const threshold = 3600 * 1000;

const timeOriginIsReliable =
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
// 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();
const navigationStart = performance.timing && performance.timing.navigationStart;
const hasNavigationStart = typeof navigationStart === 'number';
const navigationStartIsReliable =
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();
})();