diff --git a/packages/rum-recorder/src/domain/rrweb/mutation.spec.ts b/packages/rum-recorder/src/domain/rrweb/mutation.spec.ts index 9a0ee156a8..c046e41568 100644 --- a/packages/rum-recorder/src/domain/rrweb/mutation.spec.ts +++ b/packages/rum-recorder/src/domain/rrweb/mutation.spec.ts @@ -62,12 +62,12 @@ describe('MutationObserverWrapper', () => { expect(mutationCallbackSpy).not.toHaveBeenCalled() }) - it('emits buffered mutation records on freeze', () => { + it('emits buffered mutation records on flush', () => { addNodeToMap(sandbox, {}) MockMutationObserver.storeRecords([createMutationRecord()]) expect(mutationCallbackSpy).toHaveBeenCalledTimes(0) - mutationController.freeze() + mutationController.flush() expect(mutationCallbackSpy).toHaveBeenCalledTimes(1) }) diff --git a/packages/rum-recorder/src/domain/rrweb/mutation.ts b/packages/rum-recorder/src/domain/rrweb/mutation.ts index 2f983bdc45..222086d6f3 100644 --- a/packages/rum-recorder/src/domain/rrweb/mutation.ts +++ b/packages/rum-recorder/src/domain/rrweb/mutation.ts @@ -102,33 +102,17 @@ function isINode(n: Node | INode): n is INode { } /** - * Controls how mutations are processed, allowing to temporarily freeze the mutations process. + * Controls how mutations are processed, allowing to flush pending mutations. */ export class MutationController { - private frozen = false - private unfreezeListener?: () => void - private freezeListener?: () => void + private flushListener?: () => void - public freeze() { - this.freezeListener?.() - this.frozen = true + public flush() { + this.flushListener?.() } - public unfreeze() { - this.unfreezeListener?.() - this.frozen = false - } - - public isFrozen() { - return this.frozen - } - - public onFreeze(listener: () => void) { - this.freezeListener = listener - } - - public onUnfreeze(listener: () => void) { - this.unfreezeListener = listener + public onFlush(listener: () => void) { + this.flushListener = listener } } @@ -175,8 +159,7 @@ export class MutationObserverWrapper { childList: true, subtree: true, }) - this.controller.onFreeze(() => this.processMutations(this.observer.takeRecords())) - this.controller.onUnfreeze(this.emit) + this.controller.onFlush(() => this.processMutations(this.observer.takeRecords())) } public stop() { @@ -185,9 +168,7 @@ export class MutationObserverWrapper { private processMutations = (mutations: MutationRecord[]) => { mutations.forEach(this.processMutation) - if (!this.controller.isFrozen()) { - this.emit() - } + this.emit() } private emit = () => { diff --git a/packages/rum-recorder/src/domain/rrweb/record.ts b/packages/rum-recorder/src/domain/rrweb/record.ts index cd3f1dc49a..6417d63cc8 100644 --- a/packages/rum-recorder/src/domain/rrweb/record.ts +++ b/packages/rum-recorder/src/domain/rrweb/record.ts @@ -1,13 +1,11 @@ import { runOnReadyState } from '@datadog/browser-core' import { snapshot } from '../rrweb-snapshot' -import { RawRecord, RecordType } from '../../types' +import { RecordType } from '../../types' import { initObservers } from './observer' import { IncrementalSource, ListenerHandler, RecordAPI, RecordOptions } from './types' import { getWindowHeight, getWindowWidth, mirror } from './utils' import { MutationController } from './mutation' -let wrappedEmit!: (record: RawRecord, isCheckout?: boolean) => void - export function record(options: RecordOptions = {}): RecordAPI { const { emit } = options // runtime checks for user options @@ -17,25 +15,10 @@ export function record(options: RecordOptions = {}): RecordAPI { const mutationController = new MutationController() - wrappedEmit = (record, isCheckout) => { - if ( - mutationController.isFrozen() && - record.type !== RecordType.FullSnapshot && - !(record.type === RecordType.IncrementalSnapshot && record.data.source === IncrementalSource.Mutation) - ) { - // we've got a user initiated record so first we need to apply - // all DOM changes that have been buffering during paused state - mutationController.unfreeze() - } - - emit(record, isCheckout) - } - const takeFullSnapshot = (isCheckout = false) => { - const wasFrozen = mutationController.isFrozen() - mutationController.freeze() // don't allow any mirror modifications during snapshotting + mutationController.flush() // process any pending mutation before taking a full snapshot - wrappedEmit( + emit( { data: { height: getWindowHeight(), @@ -47,7 +30,7 @@ export function record(options: RecordOptions = {}): RecordAPI { isCheckout ) - wrappedEmit( + emit( { data: { has_focus: document.hasFocus(), @@ -64,7 +47,7 @@ export function record(options: RecordOptions = {}): RecordAPI { } mirror.map = idNodeMap - wrappedEmit({ + emit({ data: { node, initialOffset: { @@ -86,9 +69,6 @@ export function record(options: RecordOptions = {}): RecordAPI { }, type: RecordType.FullSnapshot, }) - if (!wasFrozen) { - mutationController.unfreeze() - } } const handlers: ListenerHandler[] = [] @@ -99,7 +79,7 @@ export function record(options: RecordOptions = {}): RecordAPI { initObservers({ mutationController, inputCb: (v) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.Input, ...v, @@ -107,7 +87,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), mediaInteractionCb: (p) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.MediaInteraction, ...p, @@ -115,7 +95,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), mouseInteractionCb: (d) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.MouseInteraction, ...d, @@ -123,7 +103,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), mousemoveCb: (positions, source) => - wrappedEmit({ + emit({ data: { positions, source, @@ -131,7 +111,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), mutationCb: (m) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.Mutation, ...m, @@ -139,7 +119,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), scrollCb: (p) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.Scroll, ...p, @@ -147,7 +127,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), styleSheetRuleCb: (r) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.StyleSheetRule, ...r, @@ -155,7 +135,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), viewportResizeCb: (d) => - wrappedEmit({ + emit({ data: { source: IncrementalSource.ViewportResize, ...d, @@ -163,7 +143,7 @@ export function record(options: RecordOptions = {}): RecordAPI { type: RecordType.IncrementalSnapshot, }), focusCb: (data) => - wrappedEmit({ + emit({ type: RecordType.Focus, data, }),