UNPKG

2.37 kBPlain TextView Raw
1/*
2 * Copyright 2020 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import {initMetric} from './lib/initMetric.js';
18import {ReportHandler, NavigationTimingPolyfillEntry} from './types.js';
19
20
21const afterLoad = (callback: () => void) => {
22 if (document.readyState === 'complete') {
23 // Queue a task so the callback runs after `loadEventEnd`.
24 setTimeout(callback, 0);
25 } else {
26 // Use `pageshow` so the callback runs after `loadEventEnd`.
27 addEventListener('pageshow', callback);
28 }
29}
30
31const getNavigationEntryFromPerformanceTiming = (): NavigationTimingPolyfillEntry => {
32 // Really annoying that TypeScript errors when using `PerformanceTiming`.
33 const timing = performance.timing;
34
35 const navigationEntry: {[key: string]: number | string} = {
36 entryType: 'navigation',
37 startTime: 0,
38 };
39
40 for (const key in timing) {
41 if (key !== 'navigationStart' && key !== 'toJSON') {
42 navigationEntry[key] = Math.max(
43 (timing[key as keyof PerformanceTiming] as number) -
44 timing.navigationStart, 0);
45 }
46 }
47 return navigationEntry as NavigationTimingPolyfillEntry;
48};
49
50export const getTTFB = (onReport: ReportHandler) => {
51 const metric = initMetric('TTFB');
52
53 afterLoad(() => {
54 try {
55 // Use the NavigationTiming L2 entry if available.
56 const navigationEntry = performance.getEntriesByType('navigation')[0] ||
57 getNavigationEntryFromPerformanceTiming();
58
59 metric.value = metric.delta =
60 (navigationEntry as PerformanceNavigationTiming).responseStart;
61
62 // In some cases the value reported is negative. Ignore these cases:
63 // https://github.com/GoogleChrome/web-vitals/issues/137
64 if (metric.value < 0) return;
65
66 metric.entries = [navigationEntry];
67
68 onReport(metric);
69 } catch (error) {
70 // Do nothing.
71 }
72 });
73};