resolve #4 Improve timer's performance by storing all callbacks in an array (#5)

This commit is contained in:
edwardwu
2026-04-01 12:00:00 +08:00
committed by YUyz
parent 92faf502d0
commit 05530551df
3 changed files with 102 additions and 52 deletions

View File

@@ -1,38 +1,70 @@
import { playerConfig } from '../types';
import { playerConfig, actionWithDelay } from '../types';
const FRAME_MS = 16;
let _id = 1;
const timerMap: Map<number, boolean> = new Map();
export default class Timer {
private actions: actionWithDelay[];
private config: playerConfig;
export function later(
cb: () => void,
delayMs: number,
config: playerConfig,
): number {
const now = performance.now();
let lastStep = now;
const id = _id++;
timerMap.set(id, true);
function check(step: number) {
if (!timerMap.has(id)) {
return;
}
const stepDiff = step - lastStep;
lastStep = step;
delayMs -= config.speed * stepDiff;
if (delayMs < FRAME_MS) {
cb();
clear(id);
} else {
requestAnimationFrame(check);
}
constructor(config: playerConfig, actions: actionWithDelay[] = []) {
this.actions = actions;
this.config = config;
}
/**
* Add an action after the timer starts.
* @param action
*/
public addAction(action: actionWithDelay) {
const index = this.findActionIndex(action);
this.actions.splice(index, 0, action);
}
/**
* Add all actions before the timer starts
* @param actions
*/
public addActions(actions: actionWithDelay[]) {
this.actions.push(...actions);
}
requestAnimationFrame(check);
return id;
}
public start() {
this.actions.sort((a1, a2) => a1.delay - a2.delay);
let delayed = 0;
const start = performance.now();
const { actions, config } = this;
function check(time: number) {
delayed = time - start;
while (actions.length) {
const action = actions[0];
const delayNeeded = action.delay / config.speed;
if (delayed >= delayNeeded) {
actions.shift();
action.doAction();
} else {
break;
}
}
if (actions.length > 0) {
requestAnimationFrame(check);
}
}
requestAnimationFrame(check);
}
export function clear(id: number) {
timerMap.delete(id);
public clear() {
this.actions = [];
}
private findActionIndex(action: actionWithDelay): number {
let start = 0;
let end = this.actions.length - 1;
while (start <= end) {
let mid = Math.floor((start + end) / 2);
if (this.actions[mid].delay < action.delay) {
start = mid + 1;
} else if (this.actions[mid].delay > action.delay) {
end = mid - 1;
} else {
return mid;
}
}
return start;
}
}