perf: Avoid an extra function call and object clone during event emission (#1441)
performance: remove a nested function call and an object clone during event emission - rename `event` to `eventWithoutTime`, but maintain backwards compatibility - `eventWithTime` (with time) could be renamed to `event` in a future version This is an extension of PR #1339 authored by: mydea <mydea@users.noreply.github.com>
This commit is contained in:
5
.changeset/event-single-wrap.md
Normal file
5
.changeset/event-single-wrap.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'rrweb': patch
|
||||
---
|
||||
|
||||
perf: Avoid an extra function call and object clone during event emission
|
||||
@@ -3,7 +3,11 @@ import { genId, NodeType } from 'rrweb-snapshot';
|
||||
import type { CrossOriginIframeMessageEvent } from '../types';
|
||||
import CrossOriginIframeMirror from './cross-origin-iframe-mirror';
|
||||
import { EventType, IncrementalSource } from '@rrweb/types';
|
||||
import type { eventWithTime, mutationCallBack } from '@rrweb/types';
|
||||
import type {
|
||||
eventWithTime,
|
||||
eventWithoutTime,
|
||||
mutationCallBack,
|
||||
} from '@rrweb/types';
|
||||
import type { StylesheetManager } from './stylesheet-manager';
|
||||
|
||||
export class IframeManager {
|
||||
@@ -16,7 +20,7 @@ export class IframeManager {
|
||||
new WeakMap();
|
||||
private mirror: Mirror;
|
||||
private mutationCb: mutationCallBack;
|
||||
private wrappedEmit: (e: eventWithTime, isCheckout?: boolean) => void;
|
||||
private wrappedEmit: (e: eventWithoutTime, isCheckout?: boolean) => void;
|
||||
private loadListener?: (iframeEl: HTMLIFrameElement) => unknown;
|
||||
private stylesheetManager: StylesheetManager;
|
||||
private recordCrossOriginIframes: boolean;
|
||||
@@ -26,7 +30,7 @@ export class IframeManager {
|
||||
mutationCb: mutationCallBack;
|
||||
stylesheetManager: StylesheetManager;
|
||||
recordCrossOriginIframes: boolean;
|
||||
wrappedEmit: (e: eventWithTime, isCheckout?: boolean) => void;
|
||||
wrappedEmit: (e: eventWithoutTime, isCheckout?: boolean) => void;
|
||||
}) {
|
||||
this.mutationCb = options.mutationCb;
|
||||
this.wrappedEmit = options.wrappedEmit;
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
import type { recordOptions } from '../types';
|
||||
import {
|
||||
EventType,
|
||||
event,
|
||||
eventWithoutTime,
|
||||
eventWithTime,
|
||||
IncrementalSource,
|
||||
listenerHandler,
|
||||
@@ -40,14 +40,7 @@ import {
|
||||
unregisterErrorHandler,
|
||||
} from './error-handler';
|
||||
|
||||
function wrapEvent(e: event): eventWithTime {
|
||||
return {
|
||||
...e,
|
||||
timestamp: nowTimestamp(),
|
||||
};
|
||||
}
|
||||
|
||||
let wrappedEmit!: (e: eventWithTime, isCheckout?: boolean) => void;
|
||||
let wrappedEmit!: (e: eventWithoutTime, isCheckout?: boolean) => void;
|
||||
|
||||
let takeFullSnapshot!: (isCheckout?: boolean) => void;
|
||||
let canvasManager!: CanvasManager;
|
||||
@@ -187,7 +180,9 @@ function record<T = eventWithTime>(
|
||||
}
|
||||
return e as unknown as T;
|
||||
};
|
||||
wrappedEmit = (e: eventWithTime, isCheckout?: boolean) => {
|
||||
wrappedEmit = (r: eventWithoutTime, isCheckout?: boolean) => {
|
||||
const e = r as eventWithTime;
|
||||
e.timestamp = nowTimestamp();
|
||||
if (
|
||||
mutationBuffers[0]?.isFrozen() &&
|
||||
e.type !== EventType.FullSnapshot &&
|
||||
@@ -238,47 +233,39 @@ function record<T = eventWithTime>(
|
||||
};
|
||||
|
||||
const wrappedMutationEmit = (m: mutationCallbackParam) => {
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Mutation,
|
||||
...m,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
const wrappedScrollEmit: scrollCallback = (p) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Scroll,
|
||||
...p,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
const wrappedCanvasMutationEmit = (p: canvasMutationParam) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.CanvasMutation,
|
||||
...p,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
const wrappedAdoptedStyleSheetEmit = (a: adoptedStyleSheetParam) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.AdoptedStyleSheet,
|
||||
...a,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
const stylesheetManager = new StylesheetManager({
|
||||
mutationCb: wrappedMutationEmit,
|
||||
@@ -350,14 +337,14 @@ function record<T = eventWithTime>(
|
||||
return;
|
||||
}
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
{
|
||||
type: EventType.Meta,
|
||||
data: {
|
||||
href: window.location.href,
|
||||
width: getWindowWidth(),
|
||||
height: getWindowHeight(),
|
||||
},
|
||||
}),
|
||||
},
|
||||
isCheckout,
|
||||
);
|
||||
|
||||
@@ -406,13 +393,13 @@ function record<T = eventWithTime>(
|
||||
}
|
||||
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
{
|
||||
type: EventType.FullSnapshot,
|
||||
data: {
|
||||
node,
|
||||
initialOffset: getWindowScroll(window),
|
||||
},
|
||||
}),
|
||||
},
|
||||
isCheckout,
|
||||
);
|
||||
mutationBuffers.forEach((buf) => buf.unlock()); // generate & emit any mutations that happened during snapshotting, as can now apply against the newly built mirror
|
||||
@@ -433,108 +420,88 @@ function record<T = eventWithTime>(
|
||||
{
|
||||
mutationCb: wrappedMutationEmit,
|
||||
mousemoveCb: (positions, source) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source,
|
||||
positions,
|
||||
},
|
||||
}),
|
||||
),
|
||||
mouseInteractionCb: (d) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.MouseInteraction,
|
||||
...d,
|
||||
},
|
||||
}),
|
||||
),
|
||||
scrollCb: wrappedScrollEmit,
|
||||
viewportResizeCb: (d) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.ViewportResize,
|
||||
...d,
|
||||
},
|
||||
}),
|
||||
),
|
||||
inputCb: (v) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Input,
|
||||
...v,
|
||||
},
|
||||
}),
|
||||
),
|
||||
mediaInteractionCb: (p) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.MediaInteraction,
|
||||
...p,
|
||||
},
|
||||
}),
|
||||
),
|
||||
styleSheetRuleCb: (r) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.StyleSheetRule,
|
||||
...r,
|
||||
},
|
||||
}),
|
||||
),
|
||||
styleDeclarationCb: (r) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.StyleDeclaration,
|
||||
...r,
|
||||
},
|
||||
}),
|
||||
),
|
||||
canvasMutationCb: wrappedCanvasMutationEmit,
|
||||
fontCb: (p) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Font,
|
||||
...p,
|
||||
},
|
||||
}),
|
||||
),
|
||||
selectionCb: (p) => {
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.Selection,
|
||||
...p,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
customElementCb: (c) => {
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.IncrementalSnapshot,
|
||||
data: {
|
||||
source: IncrementalSource.CustomElement,
|
||||
...c,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
},
|
||||
blockClass,
|
||||
ignoreClass,
|
||||
@@ -570,15 +537,13 @@ function record<T = eventWithTime>(
|
||||
observer: p.observer!,
|
||||
options: p.options,
|
||||
callback: (payload: object) =>
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.Plugin,
|
||||
data: {
|
||||
plugin: p.name,
|
||||
payload,
|
||||
},
|
||||
}),
|
||||
),
|
||||
})) || [],
|
||||
},
|
||||
hooks,
|
||||
@@ -607,12 +572,10 @@ function record<T = eventWithTime>(
|
||||
} else {
|
||||
handlers.push(
|
||||
on('DOMContentLoaded', () => {
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.DomContentLoaded,
|
||||
data: {},
|
||||
}),
|
||||
);
|
||||
});
|
||||
if (recordAfter === 'DOMContentLoaded') init();
|
||||
}),
|
||||
);
|
||||
@@ -620,12 +583,10 @@ function record<T = eventWithTime>(
|
||||
on(
|
||||
'load',
|
||||
() => {
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.Load,
|
||||
data: {},
|
||||
}),
|
||||
);
|
||||
});
|
||||
if (recordAfter === 'load') init();
|
||||
},
|
||||
window,
|
||||
@@ -648,15 +609,13 @@ record.addCustomEvent = <T>(tag: string, payload: T) => {
|
||||
if (!recording) {
|
||||
throw new Error('please add custom event after start recording');
|
||||
}
|
||||
wrappedEmit(
|
||||
wrapEvent({
|
||||
wrappedEmit({
|
||||
type: EventType.Custom,
|
||||
data: {
|
||||
tag,
|
||||
payload,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
record.freezePage = () => {
|
||||
|
||||
@@ -3,10 +3,10 @@ import {
|
||||
EventType,
|
||||
IncrementalSource,
|
||||
eventWithTime,
|
||||
eventWithoutTime,
|
||||
MouseInteractions,
|
||||
Optional,
|
||||
mouseInteractionData,
|
||||
event,
|
||||
pluginEvent,
|
||||
} from '@rrweb/types';
|
||||
import type { recordOptions } from '../src/types';
|
||||
@@ -228,7 +228,7 @@ function stringifySnapshots(snapshots: eventWithTime[]): string {
|
||||
}
|
||||
}
|
||||
delete (s as Optional<eventWithTime, 'timestamp'>).timestamp;
|
||||
return s as event;
|
||||
return s as eventWithoutTime;
|
||||
}),
|
||||
null,
|
||||
2,
|
||||
|
||||
@@ -163,7 +163,7 @@ export type incrementalData =
|
||||
| adoptedStyleSheetData
|
||||
| customElementData;
|
||||
|
||||
export type event =
|
||||
export type eventWithoutTime =
|
||||
| domContentLoadedEvent
|
||||
| loadedEvent
|
||||
| fullSnapshotEvent
|
||||
@@ -172,7 +172,13 @@ export type event =
|
||||
| customEvent
|
||||
| pluginEvent;
|
||||
|
||||
export type eventWithTime = event & {
|
||||
/**
|
||||
* @deprecated intended for internal use
|
||||
* a synonym for eventWithoutTime
|
||||
*/
|
||||
export type event = eventWithoutTime;
|
||||
|
||||
export type eventWithTime = eventWithoutTime & {
|
||||
timestamp: number;
|
||||
delay?: number;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user