Schedulers: Fix race condition, get rid of isPrimary
This commit is contained in:
parent
cafbaf91df
commit
752d131e12
@ -65,37 +65,21 @@ export function throttle<F extends AnyToVoidFunction>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function fastRafWithFallback<F extends AnyToVoidFunction>(fn: F) {
|
export function fastRafWithFallback<F extends AnyToVoidFunction>(fn: F) {
|
||||||
return fastRaf(fn, false, true);
|
return fastRaf(fn, true);
|
||||||
}
|
|
||||||
|
|
||||||
export function fastRafPrimaryWithFallback<F extends AnyToVoidFunction>(fn: F) {
|
|
||||||
return fastRaf(fn, true, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function throttleWithRafFallback<F extends AnyToVoidFunction>(fn: F) {
|
export function throttleWithRafFallback<F extends AnyToVoidFunction>(fn: F) {
|
||||||
return throttleWith(fastRafWithFallback, fn);
|
return throttleWith(fastRafWithFallback, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function throttleWithPrimaryRafFallback<F extends AnyToVoidFunction>(fn: F) {
|
|
||||||
return throttleWith(fastRafPrimaryWithFallback, fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function throttleWithRaf<F extends AnyToVoidFunction>(fn: F) {
|
export function throttleWithRaf<F extends AnyToVoidFunction>(fn: F) {
|
||||||
return throttleWith(fastRaf, fn);
|
return throttleWith(fastRaf, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function throttleWithPrimaryRaf<F extends AnyToVoidFunction>(fn: F) {
|
|
||||||
return throttleWith(fastRafPrimary, fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function throttleWithTickEnd<F extends AnyToVoidFunction>(fn: F) {
|
export function throttleWithTickEnd<F extends AnyToVoidFunction>(fn: F) {
|
||||||
return throttleWith(onTickEnd, fn);
|
return throttleWith(onTickEnd, fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function throttleWithPrimaryTickEnd<F extends AnyToVoidFunction>(fn: F) {
|
|
||||||
return throttleWith(onTickEndPrimary, fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function throttleWith<F extends AnyToVoidFunction>(schedulerFn: Scheduler, fn: F) {
|
export function throttleWith<F extends AnyToVoidFunction>(schedulerFn: Scheduler, fn: F) {
|
||||||
let waiting = false;
|
let waiting = false;
|
||||||
let args: Parameters<F>;
|
let args: Parameters<F>;
|
||||||
@ -134,102 +118,78 @@ export function rafPromise() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let fastRafCallbacks: NoneToVoidFunction[] | undefined;
|
|
||||||
let fastRafPrimaryCallbacks: NoneToVoidFunction[] | undefined;
|
|
||||||
let timeoutCallbacks: NoneToVoidFunction[] | undefined;
|
|
||||||
let timeoutPrimaryCallbacks: NoneToVoidFunction[] | undefined;
|
|
||||||
let timeout: NodeJS.Timeout | undefined;
|
|
||||||
|
|
||||||
const FAST_RAF_TIMEOUT_FALLBACK_MS = 300;
|
const FAST_RAF_TIMEOUT_FALLBACK_MS = 300;
|
||||||
|
|
||||||
|
let fastRafCallbacks: Set<NoneToVoidFunction> | undefined;
|
||||||
|
let fastRafFallbackCallbacks: Set<NoneToVoidFunction> | undefined;
|
||||||
|
let fastRafFallbackTimeout: number | undefined;
|
||||||
|
|
||||||
// May result in an immediate execution if called from another RAF callback which was scheduled
|
// May result in an immediate execution if called from another RAF callback which was scheduled
|
||||||
// (and therefore is executed) earlier than RAF callback scheduled by `fastRaf`
|
// (and therefore is executed) earlier than RAF callback scheduled by `fastRaf`
|
||||||
export function fastRaf(callback: NoneToVoidFunction, isPrimary = false, withTimeoutFallback = false) {
|
export function fastRaf(callback: NoneToVoidFunction, withTimeoutFallback = false) {
|
||||||
if (!fastRafCallbacks) {
|
if (!fastRafCallbacks) {
|
||||||
fastRafCallbacks = !withTimeoutFallback && !isPrimary ? [callback] : [];
|
fastRafCallbacks = new Set([callback]);
|
||||||
fastRafPrimaryCallbacks = !withTimeoutFallback && isPrimary ? [callback] : [];
|
|
||||||
timeoutCallbacks = withTimeoutFallback && !isPrimary ? [callback] : [];
|
|
||||||
timeoutPrimaryCallbacks = withTimeoutFallback && isPrimary ? [callback] : [];
|
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
const currentCallbacks = fastRafCallbacks!;
|
const currentCallbacks = fastRafCallbacks!;
|
||||||
const currentPrimaryCallbacks = fastRafPrimaryCallbacks!;
|
|
||||||
const currentTimeoutCallbacks = timeoutCallbacks!;
|
|
||||||
const currentTimeoutPrimaryCallbacks = timeoutPrimaryCallbacks!;
|
|
||||||
|
|
||||||
if (timeout) clearTimeout(timeout);
|
|
||||||
timeout = undefined;
|
|
||||||
|
|
||||||
fastRafCallbacks = undefined;
|
fastRafCallbacks = undefined;
|
||||||
fastRafPrimaryCallbacks = undefined;
|
fastRafFallbackCallbacks = undefined;
|
||||||
timeoutCallbacks = undefined;
|
|
||||||
timeoutPrimaryCallbacks = undefined;
|
if (fastRafFallbackTimeout) {
|
||||||
|
clearTimeout(fastRafFallbackTimeout);
|
||||||
|
fastRafFallbackTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
currentPrimaryCallbacks.forEach((cb) => cb());
|
|
||||||
currentTimeoutPrimaryCallbacks.forEach((cb) => cb());
|
|
||||||
currentCallbacks.forEach((cb) => cb());
|
currentCallbacks.forEach((cb) => cb());
|
||||||
currentTimeoutCallbacks.forEach((cb) => cb());
|
|
||||||
});
|
});
|
||||||
} else if (isPrimary) {
|
|
||||||
if (withTimeoutFallback) {
|
|
||||||
timeoutPrimaryCallbacks!.push(callback);
|
|
||||||
} else {
|
|
||||||
fastRafPrimaryCallbacks!.push(callback);
|
|
||||||
}
|
|
||||||
} else if (withTimeoutFallback) {
|
|
||||||
timeoutCallbacks!.push(callback);
|
|
||||||
} else {
|
} else {
|
||||||
fastRafCallbacks.push(callback);
|
fastRafCallbacks.add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!timeout && withTimeoutFallback) {
|
if (withTimeoutFallback) {
|
||||||
timeout = setTimeout(() => {
|
if (!fastRafFallbackCallbacks) {
|
||||||
const currentTimeoutCallbacks = timeoutCallbacks!;
|
fastRafFallbackCallbacks = new Set([callback]);
|
||||||
const currentTimeoutPrimaryCallbacks = timeoutPrimaryCallbacks!;
|
} else {
|
||||||
|
fastRafFallbackCallbacks.add(callback);
|
||||||
|
}
|
||||||
|
|
||||||
if (timeout) clearTimeout(timeout);
|
if (!fastRafFallbackTimeout) {
|
||||||
timeout = undefined;
|
fastRafFallbackTimeout = window.setTimeout(() => {
|
||||||
|
const currentTimeoutCallbacks = fastRafFallbackCallbacks!;
|
||||||
|
|
||||||
timeoutCallbacks = [];
|
if (fastRafCallbacks) {
|
||||||
timeoutPrimaryCallbacks = [];
|
currentTimeoutCallbacks.forEach(fastRafCallbacks.delete, fastRafCallbacks);
|
||||||
|
}
|
||||||
|
fastRafFallbackCallbacks = undefined;
|
||||||
|
|
||||||
currentTimeoutPrimaryCallbacks.forEach((cb) => cb());
|
if (fastRafFallbackTimeout) {
|
||||||
currentTimeoutCallbacks.forEach((cb) => cb());
|
clearTimeout(fastRafFallbackTimeout);
|
||||||
}, FAST_RAF_TIMEOUT_FALLBACK_MS);
|
fastRafFallbackTimeout = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTimeoutCallbacks.forEach((cb) => cb());
|
||||||
|
}, FAST_RAF_TIMEOUT_FALLBACK_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fastRafPrimary(callback: NoneToVoidFunction) {
|
|
||||||
fastRaf(callback, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let onTickEndCallbacks: NoneToVoidFunction[] | undefined;
|
let onTickEndCallbacks: NoneToVoidFunction[] | undefined;
|
||||||
let onTickEndPrimaryCallbacks: NoneToVoidFunction[] | undefined;
|
|
||||||
|
|
||||||
export function onTickEnd(callback: NoneToVoidFunction, isPrimary = false) {
|
export function onTickEnd(callback: NoneToVoidFunction) {
|
||||||
if (!onTickEndCallbacks) {
|
if (!onTickEndCallbacks) {
|
||||||
onTickEndCallbacks = isPrimary ? [] : [callback];
|
onTickEndCallbacks = [callback];
|
||||||
onTickEndPrimaryCallbacks = isPrimary ? [callback] : [];
|
|
||||||
|
|
||||||
Promise.resolve().then(() => {
|
Promise.resolve().then(() => {
|
||||||
const currentCallbacks = onTickEndCallbacks!;
|
const currentCallbacks = onTickEndCallbacks!;
|
||||||
const currentPrimaryCallbacks = onTickEndPrimaryCallbacks!;
|
|
||||||
onTickEndCallbacks = undefined;
|
onTickEndCallbacks = undefined;
|
||||||
onTickEndPrimaryCallbacks = undefined;
|
|
||||||
currentPrimaryCallbacks.forEach((cb) => cb());
|
|
||||||
currentCallbacks.forEach((cb) => cb());
|
currentCallbacks.forEach((cb) => cb());
|
||||||
});
|
});
|
||||||
} else if (isPrimary) {
|
|
||||||
onTickEndPrimaryCallbacks!.push(callback);
|
|
||||||
} else {
|
} else {
|
||||||
onTickEndCallbacks.push(callback);
|
onTickEndCallbacks.push(callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onTickEndPrimary(callback: NoneToVoidFunction) {
|
|
||||||
onTickEnd(callback, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
let beforeUnloadCallbacks: NoneToVoidFunction[] | undefined;
|
let beforeUnloadCallbacks: NoneToVoidFunction[] | undefined;
|
||||||
|
|
||||||
export function onBeforeUnload(callback: NoneToVoidFunction, isLast = false) {
|
export function onBeforeUnload(callback: NoneToVoidFunction, isLast = false) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user