129 lines
5.4 KiB
JavaScript
129 lines
5.4 KiB
JavaScript
import { GLOBAL_OBJ } from './worldwide.js';
|
|
|
|
const ONE_SECOND_IN_MS = 1000;
|
|
|
|
/**
|
|
* A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance}
|
|
* for accessing a high-resolution monotonic clock.
|
|
*/
|
|
|
|
/**
|
|
* Returns a timestamp in seconds since the UNIX epoch using the Date API.
|
|
*
|
|
* TODO(v8): Return type should be rounded.
|
|
*/
|
|
function dateTimestampInSeconds() {
|
|
return Date.now() / ONE_SECOND_IN_MS;
|
|
}
|
|
|
|
/**
|
|
* Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not
|
|
* support the API.
|
|
*
|
|
* Wrapping the native API works around differences in behavior from different browsers.
|
|
*/
|
|
function createUnixTimestampInSecondsFunc() {
|
|
const { performance } = GLOBAL_OBJ ;
|
|
if (!performance || !performance.now) {
|
|
return dateTimestampInSeconds;
|
|
}
|
|
|
|
// Some browser and environments don't have a timeOrigin, so we fallback to
|
|
// using Date.now() to compute the starting time.
|
|
const approxStartingTimeOrigin = Date.now() - performance.now();
|
|
const timeOrigin = performance.timeOrigin == undefined ? approxStartingTimeOrigin : performance.timeOrigin;
|
|
|
|
// performance.now() is a monotonic clock, which means it starts at 0 when the process begins. To get the current
|
|
// wall clock time (actual UNIX timestamp), we need to add the starting time origin and the current time elapsed.
|
|
//
|
|
// TODO: This does not account for the case where the monotonic clock that powers performance.now() drifts from the
|
|
// wall clock time, which causes the returned timestamp to be inaccurate. We should investigate how to detect and
|
|
// correct for this.
|
|
// See: https://github.com/getsentry/sentry-javascript/issues/2590
|
|
// See: https://github.com/mdn/content/issues/4713
|
|
// See: https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6
|
|
return () => {
|
|
return (timeOrigin + performance.now()) / ONE_SECOND_IN_MS;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the
|
|
* availability of the Performance API.
|
|
*
|
|
* BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is
|
|
* asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The
|
|
* skew can grow to arbitrary amounts like days, weeks or months.
|
|
* See https://github.com/getsentry/sentry-javascript/issues/2590.
|
|
*/
|
|
const timestampInSeconds = createUnixTimestampInSecondsFunc();
|
|
|
|
/**
|
|
* Re-exported with an old name for backwards-compatibility.
|
|
* TODO (v8): Remove this
|
|
*
|
|
* @deprecated Use `timestampInSeconds` instead.
|
|
*/
|
|
const timestampWithMs = timestampInSeconds;
|
|
|
|
/**
|
|
* Internal helper to store what is the source of browserPerformanceTimeOrigin below. For debugging only.
|
|
*/
|
|
let _browserPerformanceTimeOriginMode;
|
|
|
|
/**
|
|
* The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the
|
|
* performance API is available.
|
|
*/
|
|
const browserPerformanceTimeOrigin = (() => {
|
|
// 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 } = GLOBAL_OBJ ;
|
|
if (!performance || !performance.now) {
|
|
_browserPerformanceTimeOriginMode = 'none';
|
|
return undefined;
|
|
}
|
|
|
|
const threshold = 3600 * 1000;
|
|
const performanceNow = performance.now();
|
|
const dateNow = Date.now();
|
|
|
|
// if timeOrigin isn't available set delta to threshold so it isn't used
|
|
const timeOriginDelta = performance.timeOrigin
|
|
? Math.abs(performance.timeOrigin + performanceNow - dateNow)
|
|
: threshold;
|
|
const timeOriginIsReliable = timeOriginDelta < threshold;
|
|
|
|
// 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
|
|
const navigationStart = performance.timing && performance.timing.navigationStart;
|
|
const hasNavigationStart = typeof navigationStart === 'number';
|
|
// if navigationStart isn't available set delta to threshold so it isn't used
|
|
const navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold;
|
|
const navigationStartIsReliable = navigationStartDelta < threshold;
|
|
|
|
if (timeOriginIsReliable || navigationStartIsReliable) {
|
|
// Use the more reliable time origin
|
|
if (timeOriginDelta <= navigationStartDelta) {
|
|
_browserPerformanceTimeOriginMode = 'timeOrigin';
|
|
return performance.timeOrigin;
|
|
} else {
|
|
_browserPerformanceTimeOriginMode = 'navigationStart';
|
|
return navigationStart;
|
|
}
|
|
}
|
|
|
|
// Either both timeOrigin and navigationStart are skewed or neither is available, fallback to Date.
|
|
_browserPerformanceTimeOriginMode = 'dateNow';
|
|
return dateNow;
|
|
})();
|
|
|
|
export { _browserPerformanceTimeOriginMode, browserPerformanceTimeOrigin, dateTimestampInSeconds, timestampInSeconds, timestampWithMs };
|
|
//# sourceMappingURL=time.js.map
|