UNPKG

@zendesk/react-measure-timing-hooks

Version:

react hooks for measuring time to interactive and time to render of components

87 lines 3.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.adjustTimestampBy = exports.ensureTimestamp = void 0; exports.getEpochCorrectedForDrift = getEpochCorrectedForDrift; const JUST_CREATED_THRESHOLD_MS_AGO = 10; /** * Ensures that the input timestamp object has both epoch and performance.now() time. * If no input is provided, it generates a new timestamp with the current time. * * why store both timestamps?: * - epoch time: for reporting absolute time / correlating with backends * - durations: for calculating durations between two timestamps, performance.now() time makes more sense * - both are needed to correctly calculate a drift-adjusted epoch time * * @param input - Partial timestamp object that may contain either epoch or now or both. * @returns Full timestamp object with both epoch and performance.now() time. */ const ensureTimestamp = (input) => { const inputEpoch = input?.epoch; const inputNow = input?.now; const hasInputEpoch = typeof inputEpoch === 'number'; const hasInputNow = typeof inputNow === 'number'; if (hasInputEpoch && hasInputNow) { return input; } if (hasInputEpoch) { const differenceFromNow = Date.now() - inputEpoch; return { epoch: inputEpoch, now: Math.abs(differenceFromNow) < JUST_CREATED_THRESHOLD_MS_AGO ? performance.now() : performance.now() + differenceFromNow, }; } if (hasInputNow) { const elapsedTimeSinceInput = performance.now() - inputNow; const epoch = Date.now() - elapsedTimeSinceInput; return { epoch, now: inputNow, }; } // no data provided, use current time return { now: performance.now(), epoch: Date.now(), }; }; exports.ensureTimestamp = ensureTimestamp; // below inspired by Datadog SDK // https://github.com/DataDog/browser-sdk/blob/16efff71b42530ead10400eb23c096b54e83fad4/packages/core/src/tools/utils/timeUtils.ts#L23-L30 /** * Navigation start slightly change on some rare cases */ let navigationStart; function getNavigationStart() { if (navigationStart === undefined) { navigationStart = performance.timing.navigationStart; } return navigationStart; } /** * Why do we need to account for drift? * - monotonic clock (performance.now()) is not guaranteed to be in sync with wall clock time (Date.now()) * - Earth’s rotation speed is not constant * - browser bugs cause the monotonic clock to not tick when the computer is asleep or when the process is throttled * @see * - https://github.com/w3c/performance-timeline/issues/206 * - https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6 * - https://issues.chromium.org/issues/41450546 */ function getEpochCorrectedForDrift({ epoch, now }) { // two different time origins const calculatedTimeOrigin = epoch - now; const navigationStartEpoch = getNavigationStart(); // apply correction only for positive drift if (calculatedTimeOrigin > navigationStartEpoch) { return Math.round(calculatedTimeOrigin + now); } return Math.round(navigationStartEpoch + now); } const adjustTimestampBy = (timestamp, adjustment) => ({ epoch: timestamp.epoch + adjustment, now: timestamp.now + adjustment, }); exports.adjustTimestampBy = adjustTimestampBy; //# sourceMappingURL=ensureTimestamp.js.map