[REF] web: sort by ASC order core/utils/timing

Part-of: odoo/odoo#112913
This commit is contained in:
Bruno Boi
2023-02-17 12:07:25 +01:00
parent db4ec2ba2f
commit 2eaedb4b8d
+69 -68
View File
@@ -1,58 +1,8 @@
/** @odoo-module **/
import { browser } from "@web/core/browser/browser";
import { onWillUnmount, useComponent } from "@odoo/owl";
/**
* Creates a version of the function where only the last call between two
* animation frames is executed before the browser's next repaint. This
* effectively throttles the function to the display's refresh rate.
* NB: The first call is always called immediately (leading edge).
*
* @template {Function} T
* @param {T} func the function to throttle
* @returns {T & { cancel: () => void }} the throttled function
*/
export function throttleForAnimation(func) {
let handle = null;
const calls = new Set();
const funcName = func.name ? `${func.name} (throttleForAnimation)` : "throttleForAnimation";
const pending = () => {
if (calls.size) {
handle = browser.requestAnimationFrame(pending);
const { args, resolve } = [...calls].pop();
calls.clear();
Promise.resolve(func.apply(this, args)).then(resolve);
} else {
handle = null;
}
};
return Object.assign(
{
/** @type {any} */
[funcName](...args) {
return new Promise((resolve) => {
const isNew = handle === null;
if (isNew) {
handle = browser.requestAnimationFrame(pending);
Promise.resolve(func.apply(this, args)).then(resolve);
} else {
calls.add({ args, resolve });
}
});
},
}[funcName],
{
cancel() {
browser.cancelAnimationFrame(handle);
calls.clear();
handle = null;
},
}
);
}
/**
* Creates and returns a new debounced version of the passed function (func)
* which will postpone its execution until after 'delay' milliseconds
@@ -103,24 +53,6 @@ export function debounce(func, delay, immediate = false) {
);
}
/**
* Hook that returns a debounced version of the given function, and cancels
* the potential pending execution on willUnmount.
* @see debounce
* @template {Function} T
* @param {T} callback
* @param {number | "animationFrame"} delay
* @param {boolean} [immediate=false] whether the function should be called on
* the leading edge instead of the trailing edge.
* @returns {T & { cancel: () => void }}
*/
export function useDebounced(callback, delay, immediate = false) {
const component = useComponent();
const debounced = debounce(callback.bind(component), delay, immediate);
onWillUnmount(() => debounced.cancel());
return debounced;
}
/**
* Function that calls recursively a request to an animation frame.
* Useful to call a function repetitively, until asked to stop, that needs constant rerendering.
@@ -144,3 +76,72 @@ export function setRecurringAnimationFrame(callback) {
return stop;
}
/**
* Creates a version of the function where only the last call between two
* animation frames is executed before the browser's next repaint. This
* effectively throttles the function to the display's refresh rate.
* NB: The first call is always called immediately (leading edge).
*
* @template {Function} T
* @param {T} func the function to throttle
* @returns {T & { cancel: () => void }} the throttled function
*/
export function throttleForAnimation(func) {
let handle = null;
const calls = new Set();
const funcName = func.name ? `${func.name} (throttleForAnimation)` : "throttleForAnimation";
const pending = () => {
if (calls.size) {
handle = browser.requestAnimationFrame(pending);
const { args, resolve } = [...calls].pop();
calls.clear();
Promise.resolve(func.apply(this, args)).then(resolve);
} else {
handle = null;
}
};
return Object.assign(
{
/** @type {any} */
[funcName](...args) {
return new Promise((resolve) => {
const isNew = handle === null;
if (isNew) {
handle = browser.requestAnimationFrame(pending);
Promise.resolve(func.apply(this, args)).then(resolve);
} else {
calls.add({ args, resolve });
}
});
},
}[funcName],
{
cancel() {
browser.cancelAnimationFrame(handle);
calls.clear();
handle = null;
},
}
);
}
// ----------------------------------- HOOKS -----------------------------------
/**
* Hook that returns a debounced version of the given function, and cancels
* the potential pending execution on willUnmount.
* @see debounce
* @template {Function} T
* @param {T} callback
* @param {number | "animationFrame"} delay
* @param {boolean} [immediate=false] whether the function should be called on
* the leading edge instead of the trailing edge.
* @returns {T & { cancel: () => void }}
*/
export function useDebounced(callback, delay, immediate = false) {
const component = useComponent();
const debounced = debounce(callback.bind(component), delay, immediate);
onWillUnmount(() => debounced.cancel());
return debounced;
}