w3c / resource-timing

Resource Timing
https://w3c.github.io/resource-timing/
Other
120 stars 35 forks source link

Expose a way to link a call to fetch to an individual PerformanceResourceTiming object #102

Open n8schloss opened 7 years ago

n8schloss commented 7 years ago

(copy and pasting from https://github.com/whatwg/fetch/issues/491)

Problem

Currently the process of linking a fetch request to a specific resource timing object is imperfect. If there are two fetch api requests for the same resource that happen within a short time it's impossible to tell exactly which fetch call initiated which request, leading to some errors in performance logging. Orthogonally, if all a developer cares about is the perf result for a single fetch, having to use the whole performance api could be cumbersome.

Solution?

The ideal solution here (imo) is for there to be a way to get a resource timing object for a specific response. This could be accomplished by adding a method to response objects that give you a promise which will eventually resolve to the PerformanceResourceTiming object once it's ready.

Thoughs?

LPardue commented 7 years ago

The problem described here is just one case of aliasing of the HTTP representation that can occur by only relying on the "name" (aka URL). HTTP Content Negotiation describes some other methods that this could occur with.

One example that I am directly aware of is making multiple range requests (Using the Range header), it is impossible to differentiate. Inferring from the content length is unfeasible because range requests could request the same range size but vary by byte index.

cdaringe commented 2 years ago

I'm not sure what the existing spec says when you don't consume the body, but it seems like there should be valuable timing state immediately on Response construction? Thus, a persistent reference to (what I assume is an underlying mutable) perf entry is probably equally acceptable vs needing a method to resolve. In other words, the instant a Response is created, perf entries are likely already existent. I assume that such entries shall be updated contingent on additional response behavior, such as reading the stream. I rarely think about the case where:

const res = await fetch(...)
await doSlowWork()
await res.json()

...and how that may/may-not impact the perf entries API, such as this. gotta hit the spec :glasses: 📖

Nonetheless, some link (direct ref, method to get immutable copy, whatever) seems warranted. Today I wrote a server-timing in parser in JS to chain to my fetch calls, as we do not have such a linkage natively.

qtow commented 1 year ago

I'm not sure if this is explicitly specified behavior, but at least Firefox and Chromium keep the URL hash in PerformanceResourceTiming.name. That should work for making the URL unique for multiple requests to the same resource. I've tested this on Firefox 114, Chrome 114, and Edge 114, all on desktop. You should do your own testing if you plan on using this trick.

This doesn't obviate the need for this issue. Exposing an easy way to get the associated PerformanceResourceTiming entry from a fetch call would be more robust and ergonomic. Giving access to a partial PerformanceResourceTiming entry before the body is consumed may also be useful, but is currently impossible.

sophiebits commented 1 month ago

It's not perfect but reading the spec, it looks like one imperfect approach you can do now is to bound the .startTime of the PerformanceResourceTiming with

const a = performance.now()
const f = fetch(...)  // no await
const b = performance.now()
await f

// later, look for performance entries where a <= prt.startTime <= b (and prt.name === requestedURL)

This should disambiguate pretty well even between concurrent requests to the same resource, as long as the performance.now() resolution is finer than the difference in start times between adjacent fetches.

Spec notes for why this works: