-
Notifications
You must be signed in to change notification settings - Fork 138
Description
While carefully and extensively testing #1924 on my site, I was noticing that the URL Metric data was not consistently being submitted when navigating between pages. It would be sent if I changed tabs (when the visibilitychange event fires), but it would not be sent at the pagehide event.
I tested in Chrome, Firefox, and Safari. (For Safari, I had to remove the onLCP part due to #1925.) My debugging approach was to add sessionStorage.setItem( 'lastLineExecuted', '{lineNumber}' ) calls at various points in the detect() function after the pagehide, pageswap, and visibilitychange events occur:
detect.js.diff
diff --git a/plugins/optimization-detective/detect.js b/plugins/optimization-detective/detect.js
index cd42fd583..65b9e7f6f 100644
--- a/plugins/optimization-detective/detect.js
+++ b/plugins/optimization-detective/detect.js
@@ -654,27 +654,6 @@ export default async function detect( {
/** @type {(LCPMetric|LCPMetricWithAttribution)[]} */
const lcpMetricCandidates = [];
- // Obtain at least one LCP candidate. More may be reported before the page finishes loading.
- await new Promise( ( resolve ) => {
- onLCP(
- /**
- * Handles an LCP metric being reported.
- *
- * @param {LCPMetric|LCPMetricWithAttribution} metric
- */
- ( metric ) => {
- lcpMetricCandidates.push( metric );
- resolve();
- },
- {
- // This avoids needing to click to finalize LCP candidate. While this is helpful for testing, it also
- // ensures that we always get an LCP candidate reported. Otherwise, the callback may never fire if the
- // user never does a click or keydown, per <https://github.com/GoogleChrome/web-vitals/blob/07f6f96/src/onLCP.ts#L99-L107>.
- reportAllChanges: true,
- }
- );
- } );
-
// Stop observing.
disconnectIntersectionObserver();
log( 'Detection is stopping.' );
@@ -748,6 +727,8 @@ export default async function detect( {
return;
}
+ sessionStorage.setItem( 'lastLineExecuted', '751' );
+
// Finalize extensions.
if ( extensions.size > 0 ) {
/** @type {Promise[]} */
@@ -809,6 +790,8 @@ export default async function detect( {
}
}
+ sessionStorage.setItem( 'lastLineExecuted', '814' );
+
/*
* Now prepare the URL Metric to be sent as JSON request body.
*/
@@ -825,12 +808,16 @@ export default async function detect( {
return;
}
- const payloadBlob = gzdecodeAvailable
+ sessionStorage.setItem( 'lastLineExecuted', '832' );
+
+ const payloadBlob = gzdecodeAvailable && ! sessionStorage.getItem( 'gzdecodeDisabled' )
? await compress( jsonBody )
: new Blob( [ jsonBody ], { type: 'application/json' } );
const percentOfBudget =
( payloadBlob.size / ( maxBodyLengthKiB * 1000 ) ) * 100;
+ sessionStorage.setItem( 'lastLineExecuted', '840' );
+
/*
* According to the fetch() spec:
* "If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error."
@@ -859,6 +846,8 @@ export default async function detect( {
);
}
+ sessionStorage.setItem( 'lastLineExecuted', '870' );
+
const message = `Sending URL Metric (${ payloadBlob.size.toLocaleString() } bytes, ${ Math.round(
percentOfBudget
) }% of ${ maxBodyLengthKiB } KiB limit):`;
@@ -887,4 +876,6 @@ export default async function detect( {
// Clean up.
breadcrumbedElementsMap.clear();
+
+ sessionStorage.setItem( 'lastLineExecuted', '901' );
}(Note that I didn't use console.trace() because Chrome doesn't seem to put these in the console when the page is being navigated away from, even when console persistence is enabled.)
In all three browsers, when gzip compression is enabled, the lastLineExecuted is usually 832 which is right before compression occurs:
performance/plugins/optimization-detective/detect.js
Lines 828 to 830 in 47eef00
| const payloadBlob = gzdecodeAvailable | |
| ? await compress( jsonBody ) | |
| : new Blob( [ jsonBody ], { type: 'application/json' } ); |
(I say usually because Chrome sometimes will go ahead and finish executing to the end of the function.)
Safari also produces an actual error in the console:
This error in Safari with the Blob doesn't occur when switching tabs to cause the URL Metric to be sent at the visibilitychange event.
However, when I try disabling gzip compression via:
sessionStorage.setItem('gzdecodeDisabled', 'true')Then the lastLineExecuted is 901 for all three browsers consistently, which is the very end of the function in Chrome, Safari, and Firefox. And more importantly, when compression is disabled, URL Metrics are consistently submitted when navigating away from a page in each of the three browsers.
This seems to indicate that it is not feasible to compress the URL Metric for submission (proposed in #1893 and implemented in #1905). Nevertheless, there is one way I tried which would allow compression to be used reliably (in Firefox and Chrome): using the beforeunload event instead of the pagehide event. There is a big downside to using the beforeunload event, however: It disables bfcache. Nevertheless, it would only be disabling bfcache when the current client is gathering URL Metrics, which should be a small percentage of the actual visitors (depending on the amount of traffic to the site, of course), for example three visitors to a given page using a mobile device would have bfcache disabled while URL Metrics are collected for their visits. I think this is an acceptable tradeoff. All this being said, Safari throws a different error related to the compressed Blob when using the beforeunload event:
Therefore, it seems using gzip compression is not going to be viable at least for the near future. This will need to be reverted for the next release.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status

