From 1afa9fb1800ee2808febc3f3aa662f62d5b1922b Mon Sep 17 00:00:00 2001 From: Eoghan Murray Date: Wed, 1 Apr 2026 12:00:00 +0800 Subject: [PATCH] Fix that `addAction` wouldn't have any effect without a stop and start (#1001) * Fix that `addAction` wouldn't have any effect without a stop and start - noticed during live mode * Remove `addActions` as it has a bug-causing replacement of `this.actions` - refactor to reuse `addAction` and add a `push` fast-track to this function for the common case of adding actions in the correct order * Apply formatting changes Co-authored-by: eoghanmurray --- packages/rrweb/src/replay/machine.ts | 4 +--- packages/rrweb/src/replay/timer.ts | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/rrweb/src/replay/machine.ts b/packages/rrweb/src/replay/machine.ts index 4409dd11..fd4ad7bf 100644 --- a/packages/rrweb/src/replay/machine.ts +++ b/packages/rrweb/src/replay/machine.ts @@ -188,7 +188,6 @@ export function createPlayerService( } const syncEvents = new Array(); - const actions = new Array(); for (const event of neededEvents) { if ( lastPlayedTimestamp && @@ -202,7 +201,7 @@ export function createPlayerService( syncEvents.push(event); } else { const castFn = getCastFn(event, false); - actions.push({ + timer.addAction({ doAction: () => { castFn(); }, @@ -212,7 +211,6 @@ export function createPlayerService( } applyEventsSynchronously(syncEvents); emitter.emit(ReplayerEvents.Flush); - timer.addActions(actions); timer.start(); }, pause(ctx) { diff --git a/packages/rrweb/src/replay/timer.ts b/packages/rrweb/src/replay/timer.ts index 6cfa95e0..89d66d4b 100644 --- a/packages/rrweb/src/replay/timer.ts +++ b/packages/rrweb/src/replay/timer.ts @@ -25,38 +25,40 @@ export class Timer { this.liveMode = config.liveMode; } /** - * Add an action after the timer starts. + * Add an action, possibly after the timer starts. */ public addAction(action: actionWithDelay) { + if ( + !this.actions.length || + this.actions[this.actions.length - 1].delay <= action.delay + ) { + // 'fast track' + this.actions.push(action); + return; + } + // binary search - events can arrive out of order in a realtime context const index = this.findActionIndex(action); this.actions.splice(index, 0, action); } - /** - * Add all actions before the timer starts - */ - public addActions(actions: actionWithDelay[]) { - this.actions = this.actions.concat(actions); - } public start() { this.timeOffset = 0; let lastTimestamp = performance.now(); - const { actions } = this; const check = () => { const time = performance.now(); this.timeOffset += (time - lastTimestamp) * this.speed; lastTimestamp = time; - while (actions.length) { - const action = actions[0]; + while (this.actions.length) { + const action = this.actions[0]; if (this.timeOffset >= action.delay) { - actions.shift(); + this.actions.shift(); action.doAction(); } else { break; } } - if (actions.length > 0 || this.liveMode) { + if (this.actions.length > 0 || this.liveMode) { this.raf = requestAnimationFrame(check); } };