nuxt
Version:
58 lines (57 loc) • 1.66 kB
JavaScript
import { queuePostFlushCb } from "vue";
//#region src/app/utils/debounce-tick.ts
/**
* Debounce an async function so that repeated calls within the same tick are
* collapsed into a single call (plus a trailing call if arguments arrived
* while the debounced call was still pending).
*
* Adapted from https://github.com/unjs/perfect-debounce with the timeout
* replaced by Vue's post-flush callback queue.
*/
function debounceTick(fn, options = {}) {
let leadingValue;
let active = false;
let resolveList = [];
let currentPromise;
let trailingArgs;
const applyFn = (_this, args) => {
const promise = _applyPromised(fn, _this, args);
currentPromise = promise;
promise.finally(() => {
currentPromise = void 0;
if (trailingArgs && !active) {
const args = trailingArgs;
trailingArgs = void 0;
applyFn(_this, args);
}
});
return promise;
};
return function(...args) {
trailingArgs = args;
if (currentPromise) return currentPromise;
return new Promise((resolve) => {
const shouldCallNow = options.leading && !active;
if (!active) {
active = true;
queuePostFlushCb(() => {
active = false;
const flushArgs = trailingArgs ?? args;
trailingArgs = void 0;
const promise = options.leading ? leadingValue : applyFn(this, flushArgs);
for (const _resolve of resolveList) _resolve(promise);
resolveList = [];
});
}
if (shouldCallNow) {
leadingValue = applyFn(this, args);
resolve(leadingValue);
} else resolveList.push(resolve);
});
};
}
async function _applyPromised(fn, _this, args) {
return await fn.apply(_this, args);
}
//#endregion
export { debounceTick };