[Perf] Fix slow animate function
This commit is contained in:
parent
a2b851e34c
commit
610574c23a
99
src/util/FrameDebugger.ts
Normal file
99
src/util/FrameDebugger.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
const RANDOM = 0.95;
|
||||||
|
const DEBOUNCE = 3000;
|
||||||
|
|
||||||
|
export default class FrameDebugger {
|
||||||
|
private durations: number[] = [];
|
||||||
|
|
||||||
|
private startedAtByFrameKey: Record<string, number | undefined> = {};
|
||||||
|
|
||||||
|
private passedFrames: string[] = [];
|
||||||
|
|
||||||
|
private timeout: number | undefined;
|
||||||
|
|
||||||
|
constructor(private name: string = '[No name]') {
|
||||||
|
}
|
||||||
|
|
||||||
|
onFrameStart(frameKey = '0') {
|
||||||
|
if (this.passedFrames.includes(frameKey)) {
|
||||||
|
// debugger
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.startedAtByFrameKey[frameKey]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startedAtByFrameKey[frameKey] = performance.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFrameEnd(frameKey = '0', onAnimationEnd?: AnyToVoidFunction) {
|
||||||
|
if (!this.startedAtByFrameKey[frameKey]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration = performance.now() - this.startedAtByFrameKey[frameKey]!;
|
||||||
|
|
||||||
|
if (this.passedFrames.includes(frameKey)) {
|
||||||
|
// debugger
|
||||||
|
}
|
||||||
|
|
||||||
|
this.passedFrames.push(frameKey);
|
||||||
|
this.durations.push(duration);
|
||||||
|
|
||||||
|
this.startedAtByFrameKey[frameKey] = undefined;
|
||||||
|
|
||||||
|
if (Math.random() < RANDOM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-restricted-globals
|
||||||
|
this.timeout = self.setTimeout(() => {
|
||||||
|
if (!this.durations.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const max = Math.max(...this.durations);
|
||||||
|
const min = Math.max(...this.durations);
|
||||||
|
const maxIndex = this.durations.indexOf(max);
|
||||||
|
const minIndex = this.durations.indexOf(min);
|
||||||
|
const reduced = this.durations.slice();
|
||||||
|
reduced.splice(maxIndex, 1);
|
||||||
|
reduced.splice(minIndex, 1);
|
||||||
|
const avg = reduced.reduce((acc, cur) => acc + cur, 0) / this.durations.length;
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log(
|
||||||
|
'!!!',
|
||||||
|
this.name,
|
||||||
|
'total frames:',
|
||||||
|
this.durations.length,
|
||||||
|
', avg duration:',
|
||||||
|
avg.toFixed(2),
|
||||||
|
', max duration:',
|
||||||
|
Math.max(...reduced).toFixed(2),
|
||||||
|
', min duration:',
|
||||||
|
Math.min(...reduced).toFixed(2),
|
||||||
|
);
|
||||||
|
|
||||||
|
onAnimationEnd?.();
|
||||||
|
|
||||||
|
this.reset();
|
||||||
|
}, DEBOUNCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
this.durations = [];
|
||||||
|
|
||||||
|
this.startedAtByFrameKey = {};
|
||||||
|
|
||||||
|
this.passedFrames = [];
|
||||||
|
|
||||||
|
if (this.timeout) {
|
||||||
|
clearTimeout(this.timeout);
|
||||||
|
this.timeout = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,9 +24,17 @@ export function animateSingle(tick: Function, instance?: AnimationInstance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function animate(tick: Function) {
|
export function animate(tick: Function) {
|
||||||
|
fastRaf(() => {
|
||||||
|
if (tick()) {
|
||||||
|
animate(tick);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function animateInstantly(tick: Function) {
|
||||||
if (tick()) {
|
if (tick()) {
|
||||||
fastRaf(() => {
|
fastRaf(() => {
|
||||||
animate(tick);
|
animateInstantly(tick);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,7 +80,7 @@ export function animateNumber({
|
|||||||
const t0 = Date.now();
|
const t0 = Date.now();
|
||||||
let canceled = false;
|
let canceled = false;
|
||||||
|
|
||||||
animate(() => {
|
animateInstantly(() => {
|
||||||
if (canceled) return false;
|
if (canceled) return false;
|
||||||
const t1 = Date.now();
|
const t1 = Date.now();
|
||||||
let t = (t1 - t0) / duration;
|
let t = (t1 - t0) / duration;
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { getGlobal } from '../global';
|
|||||||
|
|
||||||
import { ANIMATION_LEVEL_MIN } from '../config';
|
import { ANIMATION_LEVEL_MIN } from '../config';
|
||||||
import { animate } from './animation';
|
import { animate } from './animation';
|
||||||
import { fastRaf } from './schedulers';
|
|
||||||
|
|
||||||
const DEFAULT_DURATION = 300;
|
const DEFAULT_DURATION = 300;
|
||||||
|
|
||||||
@ -62,23 +61,21 @@ function scrollWithJs(container: HTMLElement, left: number, duration: number) {
|
|||||||
});
|
});
|
||||||
const startAt = Date.now();
|
const startAt = Date.now();
|
||||||
|
|
||||||
fastRaf(() => {
|
animate(() => {
|
||||||
animate(() => {
|
if (isStopped) return false;
|
||||||
if (isStopped) return false;
|
|
||||||
|
|
||||||
const t = Math.min((Date.now() - startAt) / duration, 1);
|
const t = Math.min((Date.now() - startAt) / duration, 1);
|
||||||
|
|
||||||
const currentPath = path * (1 - transition(t));
|
const currentPath = path * (1 - transition(t));
|
||||||
container.scrollLeft = Math.round(target - currentPath);
|
container.scrollLeft = Math.round(target - currentPath);
|
||||||
|
|
||||||
if (t >= 1) {
|
if (t >= 1) {
|
||||||
container.style.scrollSnapType = '';
|
container.style.scrollSnapType = '';
|
||||||
container.dataset.scrollId = undefined;
|
container.dataset.scrollId = undefined;
|
||||||
stopById.delete(id);
|
stopById.delete(id);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
return t < 1;
|
return t < 1;
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user