Closed tunetheweb closed 1 year ago
I thought of setting one PerformanceObserver with both LCP and SoftNav entries
FYI you can call .observe()
multiple times on a single PO and achieve this using buffered flag:
let entries = [];
let obs = new PerformanceObserver(list => entries.push(...list.getEntries()));
['paint','event','largest-contentful-paint','element','resource','navigation'].forEach(type => obs.observe({ type, buffered:true, durationThreshold: 0 }));
I also checked and it looks like entries are sorted so I think you'll get them in expected order-- though I'm not sure if thats guarenteed.
There's an easier solution. You CAN look up the navigation entries directly with:
NavigationId - 1
(basically 0
for the primary nav, which I think is the only one that should be used?).NavigationId - 2
So that massively reduces the complexity here. Completely forgot about that API.
Not everything is in that API, but the navigation ones are, and those are the only ones I need.
I'm trying to implemented support of this into web-vital.js.
For future events this works well. For example, for LCP events I can do the following:
I presume this will work as the events should be queued in order, so a SoftNav should always be emitted before it's first LCP entry and testing appears to show that is the case. So my first question is: Is that a valid assumption?
However, I'm running into problems when processing
buffered
events that happened before the library was initiated. The flow is basically the following:In effect, I need to synchronise the results of two different PerformanceObservers and ensure that no entries get dropped, and that no entries outstay their welcome. It's possible, but proving a bit tricky...
I thought of setting one PerformanceObserver with both LCP and SoftNav entries to allow buffered ones to be replayed in order, using
entryTypes
but that doesn't support thebuffered
flag otherwise that could work quite well and only require processing one LCP at a time (as we do currently). But, given the lack ofbuffered
support that is not an option. 😔While we're on the subject, I have an additional problem that we don't "finalize" an LCP event, until a SoftNav occurs, at which point the URL has changed. As users will want to associate the LCP event with the previous URL to send to their analytics provider, that needs to be available too. We do need to get the SoftNav entry anyway to calculate the correct LCP start time so could store the URL form that and add the URL to the metric emitted by the library, but for the initial navigation and initial LCP we don't have that URL so need to set up ANOTHER PerformanceObserver to get the initial navigation event (which is
PerformanceNavigationTiming
rather than aSoftNavigationEntry
so again slightly different). Which makes the problem even trickier as now dealing with three PerformanceObservers... Multiple that up by the 6 metrics that we track (all of which are basically currently handled independently at the moment) and it gets even more complicated.This all would be considerably simplified, if the LCP event included the Soft Navigation
startTime
(or the LCP time was based on this rather than on navigationStart) and also if it included the navigation URL it was the LCP for. Or, alternatively, if it included a reference to the navigation entry (full or soft as appropriate) that the LCP was emitted for, so I can get those two bits of information more easily. But, again, that's not currently possible AFAIK.I'm sure I've over complicated this, so any thoughts on a better way of doing this?