Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redirect time to TTFB breakdown #395

Closed
tunetheweb opened this issue Oct 18, 2023 · 5 comments
Closed

Add redirect time to TTFB breakdown #395

tunetheweb opened this issue Oct 18, 2023 · 5 comments

Comments

@tunetheweb
Copy link
Member

tunetheweb commented Oct 18, 2023

Redirects can cause considerable impact to LCP times. We should add this to TTFB attribution.

Note concerns have been raised that this is a cross-origin leak and so may be removed from Web APIs, but if that happens that will need to lead to discussions on the wider impact to Core Web Vitals (can you measure LCP accurately without this or do redirects have to move outside of LCP then?)

Also what to do with the current waitingTime measure which currently includes redirect time? Do leave as is to avoid making a breaking change? Or change in the next major release to subtract redirect time from this. Redirect time is also only part of what it measures and from the PerformanceNavigationTiming there's also unload time before it, and service worker and HTTP Cache time after it. So should they all be included and waitTime be full deprecated (but remain as is for now)?

@tunetheweb
Copy link
Member Author

tunetheweb commented Oct 19, 2023

Decided to add as additional experimental breakdowns:

  • redirectTime
  • cacheTime (including SW + HTTP Cache time)

We will leave waitingTime as is for now, but deprecate it, and drop it for v4.

So adding up the 6 metrics will not equal the total and need to add either redirectTime + cacheTime or waitingTime and the others to make the total.

@corewebvitals
Copy link

corewebvitals commented Nov 27, 2023

Good morning Barry, here is the version I use.

It's more in line with the https://www.w3.org/TR/navigation-timing-2/#processing-model
I do the starttimes a bit different because I believe it makes more sense to at-least set start to the start of the entry before it then to 0

Feel free to use .... or not :-)

attribution/onTTFB.js

/*
 * Copyright 2022 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 {onTTFB as unattributedOnTTFB} from '../onTTFB.js';
import {
  TTFBMetric,
  TTFBMetricWithAttribution,
  TTFBReportCallback,
  TTFBReportCallbackWithAttribution,
  ReportOpts,
} from '../types.js';

const attributeTTFB = (metric: TTFBMetric): void => {
  if (metric.entries.length) {
    const navigationEntry = metric.entries[0];
    const activationStart = navigationEntry.activationStart || 0;

    const workerStart = Math.max(navigationEntry.workerStart - activationStart, activationStart);
    const dnsStart = Math.max(navigationEntry.domainLookupStart - activationStart, workerStart);
    const tcpStart = Math.max(navigationEntry.connectStart - activationStart, dnsStart);
    const sslStart = Math.max(navigationEntry.secureConnectionStart - activationStart, tcpStart);
    const requestStart = Math.max(navigationEntry.requestStart - activationStart, sslStart);
    const responseStart = Math.max(navigationEntry.responseStart - activationStart, requestStart);
   
    (metric as TTFBMetricWithAttribution).attribution = {
      redirectTime: workerStart - activationStart,
      workerAndCacheTime: dnsStart - workerStart,
      dnsTime: tcpStart - dnsStart,
      tcpTime: sslStart - tcpStart,
      sslTime: requestStart - sslStart,
      requestTime: responseStart - requestStart,
      navigationEntry: navigationEntry,
    };
    return;
  }
  // Set an empty object if no other attribution has been set.
  (metric as TTFBMetricWithAttribution).attribution = {
    redirectTime: 0,
    workerAndCacheTime: 0,
    dnsTime: 0,
    tcpTime: 0,
    sslTime: 0,
    requestTime: 0
  };
};

/**
 * Calculates the [TTFB](https://web.dev/articles/ttfb) value for the
 * current page and calls the `callback` function once the page has loaded,
 * along with the relevant `navigation` performance entry used to determine the
 * value. The reported value is a `DOMHighResTimeStamp`.
 *
 * Note, this function waits until after the page is loaded to call `callback`
 * in order to ensure all properties of the `navigation` entry are populated.
 * This is useful if you want to report on other metrics exposed by the
 * [Navigation Timing API](https://w3c.github.io/navigation-timing/). For
 * example, the TTFB metric starts from the page's [time
 * origin](https://www.w3.org/TR/hr-time-2/#sec-time-origin), which means it
 * includes time spent on DNS lookup, connection negotiation, network latency,
 * and server processing time.
 */
export const onTTFB = (
  onReport: TTFBReportCallbackWithAttribution,
  opts?: ReportOpts
) => {
  unattributedOnTTFB(
    ((metric: TTFBMetricWithAttribution) => {
      attributeTTFB(metric);
      onReport(metric);
    }) as TTFBReportCallback,
    opts
  );
};

and types/ttfb.js

/*
 * Copyright 2022 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 type {Metric} from './base.js';
import {NavigationTimingPolyfillEntry} from './polyfills.js';

/**
 * A TTFB-specific version of the Metric object.
 */
export interface TTFBMetric extends Metric {
  name: 'TTFB';
  entries: PerformanceNavigationTiming[] | NavigationTimingPolyfillEntry[];
}

/**
 * An object containing potentially-helpful debugging information that
 * can be sent along with the TTFB value for the current page visit in order
 * to help identify issues happening to real-users in the field.
 */
export interface TTFBAttribution {
  
  /**
   * The total redirect time.s.
   */
  redirectTime: number;
  
  /**
   * The total worker and cache time.
   */
  workerAndCacheTime: number;
 
  /**
   * The total dns time.
   */
  dnsTime: number;
  
  /**
   * The total tcp time.
   */
  tcpTime: number;
 
  /**
   * The total ssl time.
   */
  sslTime: number;

  /**
   * The total reqquest  time.
   */
  requestTime: number;
  /**
   * The `navigation` entry of the current page, which is useful for diagnosing
   * general page load issues. This can be used to access `serverTiming` for example:
   * navigationEntry?.serverTiming
   */
  navigationEntry?: PerformanceNavigationTiming | NavigationTimingPolyfillEntry;
}

/**
 * A TTFB-specific version of the Metric object with attribution.
 */
export interface TTFBMetricWithAttribution extends TTFBMetric {
  attribution: TTFBAttribution;
}

/**
 * A TTFB-specific version of the ReportCallback function.
 */
export interface TTFBReportCallback {
  (metric: TTFBMetric): void;
}

/**
 * A TTFB-specific version of the ReportCallback function with attribution.
 */
export interface TTFBReportCallbackWithAttribution {
  (metric: TTFBMetricWithAttribution): void;
}

@vanderhoop
Copy link
Contributor

Decided to add as additional experimental breakdowns redirectTime [and] cacheTime. We will leave waitingTime as is for now, but deprecate it, and drop it for v4.

Hey @tunetheweb + @philipwalton given that the first 4.0-beta has been cut, is it fair to guess that redirectTime won't make it into v4?

@tunetheweb
Copy link
Member Author

This would be a nice one to get in before v4 since it would be a breaking change if we change waitingTime. Will have a look this week and see if we can add to v4.

@tunetheweb
Copy link
Member Author

Completed (as best as is possible) in #458

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants