diff --git a/packages/rum-core/src/common/after-frame.js b/packages/rum-core/src/common/after-frame.js index c9b545f28..f29ec7fa1 100644 --- a/packages/rum-core/src/common/after-frame.js +++ b/packages/rum-core/src/common/after-frame.js @@ -23,6 +23,8 @@ * */ +import { runInOwnZone } from './utils' + const RAF_TIMEOUT = 100 /** @@ -43,7 +45,7 @@ export default function afterFrame(callback) { cancelAnimationFrame(raf) setTimeout(callback) } - const timeout = setTimeout(handler, RAF_TIMEOUT) + const timeout = runInOwnZone(() => setTimeout(handler, RAF_TIMEOUT)) const raf = requestAnimationFrame(handler) } diff --git a/packages/rum-core/src/common/http/fetch.js b/packages/rum-core/src/common/http/fetch.js index dee06aab7..ff6094de0 100644 --- a/packages/rum-core/src/common/http/fetch.js +++ b/packages/rum-core/src/common/http/fetch.js @@ -24,6 +24,7 @@ */ import { HTTP_REQUEST_TIMEOUT } from '../constants' +import { runInOwnZone } from '../utils' import { isResponseSuccessful } from './response-status' // keepalive flag tends to limit the payload size to 64 KB @@ -60,7 +61,7 @@ export function sendFetchRequest( if (typeof AbortController === 'function') { const controller = new AbortController() timeoutConfig.signal = controller.signal - setTimeout(() => controller.abort(), timeout) + runInOwnZone(() => setTimeout(() => controller.abort(), timeout)) } let fetchResponse diff --git a/packages/rum-core/src/common/queue.js b/packages/rum-core/src/common/queue.js index 3843c0d07..9e917829f 100644 --- a/packages/rum-core/src/common/queue.js +++ b/packages/rum-core/src/common/queue.js @@ -23,6 +23,8 @@ * */ +import { runInOwnZone } from './utils' + class Queue { constructor(onFlush, opts = {}) { this.onFlush = onFlush @@ -33,7 +35,9 @@ class Queue { } _setTimer() { - this.timeoutId = setTimeout(() => this.flush(), this.flushInterval) + this.timeoutId = runInOwnZone(() => + setTimeout(() => this.flush(), this.flushInterval) + ) } _clear() { diff --git a/packages/rum-core/src/common/throttle.js b/packages/rum-core/src/common/throttle.js index 5c129b2d7..d6d7c1f11 100644 --- a/packages/rum-core/src/common/throttle.js +++ b/packages/rum-core/src/common/throttle.js @@ -23,6 +23,8 @@ * */ +import { runInOwnZone } from './utils' + export default function throttle(fn, onThrottle, opts) { var context = this var limit = opts.limit @@ -32,10 +34,12 @@ export default function throttle(fn, onThrottle, opts) { return function () { counter++ if (typeof timeoutId === 'undefined') { - timeoutId = setTimeout(function () { - counter = 0 - timeoutId = undefined - }, interval) + runInOwnZone(() => { + timeoutId = setTimeout(function () { + counter = 0 + timeoutId = undefined + }, interval) + }) } if (counter > limit && typeof onThrottle === 'function') { return onThrottle.apply(context, arguments) diff --git a/packages/rum-core/src/common/utils.js b/packages/rum-core/src/common/utils.js index bf2a7bc39..a77a002f2 100644 --- a/packages/rum-core/src/common/utils.js +++ b/packages/rum-core/src/common/utils.js @@ -431,6 +431,25 @@ function isBeaconInspectionEnabled() { return false } +/** + * Run the given function in a separate zone if ZoneJs used. + * i.e. in Angular, where this can be used to let functions like `setTimeout` and `setInterval` not block the stabilization. + * (https://angular.io/api/core/ApplicationRef#isStable) + */ +function runInOwnZone(fn) { + if (typeof window.Zone === 'undefined') { + return fn() + } + + if (!window.ApmZone) { + window.ApmZone = Zone.root.fork({ + name: 'ApmZone' + }) + } + + return window.ApmZone.run(fn) +} + export { extend, merge, @@ -470,5 +489,6 @@ export { isPerfTimelineSupported, isBrowser, isPerfTypeSupported, - isBeaconInspectionEnabled + isBeaconInspectionEnabled, + runInOwnZone } diff --git a/packages/rum-core/src/index.js b/packages/rum-core/src/index.js index 4d5efd001..18e978c69 100644 --- a/packages/rum-core/src/index.js +++ b/packages/rum-core/src/index.js @@ -32,7 +32,8 @@ import { isPlatformSupported, scheduleMicroTask, scheduleMacroTask, - isBrowser + isBrowser, + runInOwnZone } from './common/utils' import { patchAll, patchEventHandler } from './common/patching' import { observePageVisibility, observePageClicks } from './common/observers' @@ -86,5 +87,6 @@ export { CLICK, bootstrap, observePageVisibility, - observePageClicks + observePageClicks, + runInOwnZone }