diff --git a/packages/browser-utils/src/metrics/utils.ts b/packages/browser-utils/src/metrics/utils.ts index e56d0ee98d42..5caab5bc75cc 100644 --- a/packages/browser-utils/src/metrics/utils.ts +++ b/packages/browser-utils/src/metrics/utils.ts @@ -226,13 +226,21 @@ export function listenForWebVitalReportEvents( // we only want to collect LCP if we actually navigate. Redirects should be ignored. if (!options?.isRedirect) { _runCollectorCallbackOnce('navigation'); - unsubscribeStartNavigation?.(); - unsubscribeAfterStartPageLoadSpan?.(); + safeUnsubscribe(unsubscribeStartNavigation, unsubscribeAfterStartPageLoadSpan); } }); const unsubscribeAfterStartPageLoadSpan = client.on('afterStartPageLoadSpan', span => { pageloadSpanId = span.spanContext().spanId; - unsubscribeAfterStartPageLoadSpan?.(); + safeUnsubscribe(unsubscribeAfterStartPageLoadSpan); }); } + +/** + * Invoke a list of unsubscribers in a safe way, by deferring the invocation to the next tick. + * This is necessary because unsubscribing in sync can lead to other callbacks no longer being invoked + * due to in-place array mutation of the subscribers array on the client. + */ +function safeUnsubscribe(...unsubscribers: (() => void | undefined)[]): void { + unsubscribers.forEach(u => u && setTimeout(u, 0)); +}