You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
2.5 KiB
76 lines
2.5 KiB
2 years ago
|
/*
|
||
|
* Copyright 2020 Google LLC
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
import {initMetric} from './lib/initMetric.js';
|
||
|
import {ReportHandler, NavigationTimingPolyfillEntry} from './types.js';
|
||
|
|
||
|
|
||
|
const afterLoad = (callback: () => void) => {
|
||
|
if (document.readyState === 'complete') {
|
||
|
// Queue a task so the callback runs after `loadEventEnd`.
|
||
|
setTimeout(callback, 0);
|
||
|
} else {
|
||
|
// Queue a task so the callback runs after `loadEventEnd`.
|
||
|
addEventListener('load', () => setTimeout(callback, 0));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const getNavigationEntryFromPerformanceTiming = (): NavigationTimingPolyfillEntry => {
|
||
|
// Really annoying that TypeScript errors when using `PerformanceTiming`.
|
||
|
const timing = performance.timing;
|
||
|
|
||
|
const navigationEntry: {[key: string]: number | string} = {
|
||
|
entryType: 'navigation',
|
||
|
startTime: 0,
|
||
|
};
|
||
|
|
||
|
for (const key in timing) {
|
||
|
if (key !== 'navigationStart' && key !== 'toJSON') {
|
||
|
navigationEntry[key] = Math.max(
|
||
|
(timing[key as keyof PerformanceTiming] as number) -
|
||
|
timing.navigationStart, 0);
|
||
|
}
|
||
|
}
|
||
|
return navigationEntry as unknown as NavigationTimingPolyfillEntry;
|
||
|
};
|
||
|
|
||
|
export const getTTFB = (onReport: ReportHandler) => {
|
||
|
const metric = initMetric('TTFB');
|
||
|
|
||
|
afterLoad(() => {
|
||
|
try {
|
||
|
// Use the NavigationTiming L2 entry if available.
|
||
|
const navigationEntry = performance.getEntriesByType('navigation')[0] ||
|
||
|
getNavigationEntryFromPerformanceTiming();
|
||
|
|
||
|
metric.value = metric.delta =
|
||
|
(navigationEntry as PerformanceNavigationTiming).responseStart;
|
||
|
|
||
|
// In some cases the value reported is negative or is larger
|
||
|
// than the current page time. Ignore these cases:
|
||
|
// https://github.com/GoogleChrome/web-vitals/issues/137
|
||
|
// https://github.com/GoogleChrome/web-vitals/issues/162
|
||
|
if (metric.value < 0 || metric.value > performance.now()) return;
|
||
|
|
||
|
metric.entries = [navigationEntry];
|
||
|
|
||
|
onReport(metric);
|
||
|
} catch (error) {
|
||
|
// Do nothing.
|
||
|
}
|
||
|
});
|
||
|
};
|