diff --git a/src/replay/index.ts b/src/replay/index.ts index 8cdada96..7af8bf63 100644 --- a/src/replay/index.ts +++ b/src/replay/index.ts @@ -129,6 +129,8 @@ export class Replayer { events: Array, config?: Partial, ) { + events.sort((a1, a2) => a1.timestamp - a2.timestamp); + if (!config?.liveMode && events.length < 2) { throw new Error('Replayer need at least 2 events.'); } @@ -520,6 +522,8 @@ export class Replayer { castFn(); } this.service.send({ type: 'CAST_EVENT', payload: { event } }); + + // events are kept sorted by timestamp, check if this is the last event if ( event === this.service.state.context.events[ diff --git a/src/replay/machine.ts b/src/replay/machine.ts index 86459e6a..d2e3313f 100644 --- a/src/replay/machine.ts +++ b/src/replay/machine.ts @@ -237,7 +237,29 @@ export function createPlayerService( if (machineEvent.type === 'ADD_EVENT') { const { event } = machineEvent.payload; addDelay(event, baselineTime); - events.push(event); + + let end = events.length - 1; + if (events[end].timestamp <= event.timestamp) { + // fast track + events.push(event); + } else { + let insertion_index = -1; + let start = 0; + while (start <= end) { + let mid = Math.floor((start + end) / 2); + if (events[mid].timestamp <= event.timestamp) { + start = mid + 1; + } else { + end = mid - 1; + } + } + if (insertion_index === -1) { + insertion_index = start; + } + events.splice(insertion_index, 0, event); + } + + const isSync = event.timestamp < baselineTime; const castFn = getCastFn(event, isSync); if (isSync) { diff --git a/src/replay/timer.ts b/src/replay/timer.ts index e5eefa04..2d2d7c23 100644 --- a/src/replay/timer.ts +++ b/src/replay/timer.ts @@ -34,7 +34,6 @@ export class Timer { } public start() { - this.actions.sort((a1, a2) => a1.delay - a2.delay); this.timeOffset = 0; let lastTimestamp = performance.now(); const { actions } = this;