Anti-shake

Use scenarios
Rather than retrieving data for each input, you can usually retrieve it after a period of time when user input stops, as shown in the following figure:

Implementation Code
function debounce<Return>(
fn: (...params: any[]) => Return,
wait: number, /** waiting time */
immediate: boolean /** Do you want to execute it once now */
): Executor<Return> {
const now: () => number = Date.now.bind(Date);
let lastTime: number = 0;
let timer: number = null;
let params: IArguments = null;
let _this: Function | null = null;
function later(): void {
const nowTime: number = now();
if (nowTime - lastTime < wait) {
// Continue to wait if you don't have enough time to wait
const remainTime = wait - (nowTime - lastTime);
timer = setTimeout(later, remainTime);
} else {
// Wait time is up to perform callback
debouncer.result = fn.apply(_this, params);
timer = null;
_this = null;
params = null;
}
}
function execute(): (Return | null) {
lastTime = now();
_this = this;
params = arguments;
try {
if (immediate && timer === null) {
// Execute once now
debouncer.result = fn.apply(_this, params);
}
return debouncer.result;
} finally {
if (timer === null) {
// Join time queue, wait for execution
timer = setTimeout(later, wait);
}
}
}
// Create Executor
const debouncer: Executor<Return> = {
execute,
result: null,
};
return debouncer;
};
The principle is simple, mainly to determine whether the wait time has arrived or not, and if not, to continue joining the task queue for execution.Usage method:
import utils from '../index';
const input = document.querySelector('input');
const executor = utils.fn.debounce(function(value) {
console.log('fetch');
return value;
}, 300);
let value = null;
input.addEventListener('input', function(e) {
executor.execute(e.target.value);
value = executor.result;
});
The reason for returning an executor is that this makes it easy to get the value returned on the last function execution.
throttle

Use scenarios
Some events can be triggered less frequently.For example, lazy loading listens for the position of the calculated scrollbar, but it doesn't have to trigger each slide to reduce the frequency of the calculation without wasting resources; it also has the magnifying effect of making a commodity preview without having to calculate the position every time the mouse moves.
Implementation Code
throttle: function <Return>(
fn: (...params: any[]) => Return,
wait: number,
{
isExecuteAtStart = true,
isExecuteAtEnd = true,
}: ThrottleOptions = {
isExecuteAtStart: true,
isExecuteAtEnd: true,
}
): Executor<Return> {
let timer: number = null;
let _this: Function = null;
let params: IArguments = null;
function execute(): (Return | null) {
_this = this;
params = arguments;
if (isExecuteAtStart && timer === null) {
// If you need to start executing without a timer
executor.result = fn.apply(_this, params);
_this = null;
params = null;
}
if (isExecuteAtEnd) {
// If execution is required at the end
if (timer === null) {
timer = setTimeout(function () {
executor.result = fn.apply(_this, params);
_this = null;
params = null;
timer = null;
}, wait);
}
}
return executor.result;
}
const executor: Executor<Return> = {
execute,
result: null
};
return executor;
}
Last
The purpose of anti-shake and throttling is to reduce unnecessary calculations, not waste resources, and trigger calculations only when appropriate.The source code can be in This project As you can see from the fn module in, there are many other useful functions that you are welcome to use and learn.If my article is helpful to you, you can say yes. Thank you.