@iicoding/utils
Version:
Browser 端 - 类型判断 - 类似 koa 的异步compose - sleep - 扩展对象属性 - 扩展 storage 对象功能
120 lines (115 loc) • 3.65 kB
JavaScript
import { isObject } from "../index";
import root from "../global";
export function debounce(func, wait, options) {
var lastArgs;
var lastThis;
var maxWait;
var result;
var timerId;
var lastCallTime;
var lastInvokeTime = 0;
var leading = false;
var maxing = false;
var trailing = true;
// Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
var useRAF = !wait && wait !== 0 && typeof root.requestAnimationFrame === 'function';
if (typeof func !== 'function') {
throw new TypeError('Expected a function');
}
wait = +wait || 0;
if (isObject(options)) {
leading = !!options.leading;
maxing = 'maxWait' in options;
// @ts-ignore
maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
trailing = 'trailing' in options ? !!options.trailing : trailing;
}
function invokeFunc(time) {
var args = lastArgs;
var thisArg = lastThis;
lastArgs = lastThis = undefined;
lastInvokeTime = time;
result = func.apply(thisArg, args);
return result;
}
function startTimer(pendingFunc, milliseconds) {
if (useRAF) {
root.cancelAnimationFrame(timerId);
return root.requestAnimationFrame(pendingFunc);
}
return setTimeout(pendingFunc, milliseconds);
}
function cancelTimer(id) {
if (useRAF) {
root.cancelAnimationFrame(id);
return;
}
clearTimeout(id);
}
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function leadingEdge(time) {
// Reset any `maxWait` timer.
lastInvokeTime = time;
// Start the timer for the trailing edge.
timerId = startTimer(timerExpired, wait);
// Invoke the leading edge.
return leading ? invokeFunc(time) : result;
}
function remainingWait(time) {
var timeSinceLastCall = time - lastCallTime;
var timeSinceLastInvoke = time - lastInvokeTime;
var timeWaiting = wait - timeSinceLastCall;
return maxing ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
}
function shouldInvoke(time) {
var timeSinceLastCall = time - lastCallTime;
var timeSinceLastInvoke = time - lastInvokeTime;
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
}
function timerExpired() {
var time = Date.now();
if (shouldInvoke(time)) {
return trailingEdge(time);
}
// Restart the timer.
timerId = startTimer(timerExpired, remainingWait(time));
return undefined;
}
function trailingEdge(time) {
// @ts-ignore
timerId = undefined;
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if (trailing && lastArgs) {
return invokeFunc(time);
}
lastArgs = lastThis = undefined;
return result;
}
function cancel() {
if (timerId !== undefined) {
cancelTimer(timerId);
}
lastInvokeTime = 0;
// @ts-ignore
lastArgs = lastCallTime = lastThis = timerId = undefined;
}
function flush() {
return timerId === undefined ? result : trailingEdge(Date.now());
}
function pending() {
return timerId !== undefined;
}
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function debounced() {}
debounced.cancel = cancel;
debounced.flush = flush;
debounced.pending = pending;
return debounced;
}
export default debounce;