1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | import {initMetric} from './lib/initMetric.js';
|
18 | import {ReportHandler, NavigationTimingPolyfillEntry} from './types.js';
|
19 |
|
20 |
|
21 | const afterLoad = (callback: () => void) => {
|
22 | if (document.readyState === 'complete') {
|
23 |
|
24 | setTimeout(callback, 0);
|
25 | } else {
|
26 |
|
27 | addEventListener('pageshow', callback);
|
28 | }
|
29 | }
|
30 |
|
31 | const getNavigationEntryFromPerformanceTiming = (): NavigationTimingPolyfillEntry => {
|
32 |
|
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 |
|
50 | export const getTTFB = (onReport: ReportHandler) => {
|
51 | const metric = initMetric('TTFB');
|
52 |
|
53 | afterLoad(() => {
|
54 | try {
|
55 |
|
56 | const navigationEntry = performance.getEntriesByType('navigation')[0] ||
|
57 | getNavigationEntryFromPerformanceTiming();
|
58 |
|
59 | metric.value = metric.delta =
|
60 | (navigationEntry as PerformanceNavigationTiming).responseStart;
|
61 |
|
62 |
|
63 |
|
64 | if (metric.value < 0) return;
|
65 |
|
66 | metric.entries = [navigationEntry];
|
67 |
|
68 | onReport(metric);
|
69 | } catch (error) {
|
70 |
|
71 | }
|
72 | });
|
73 | };
|