当前位置:网站首页>Custom throttling function six steps to deal with complex requirements
Custom throttling function six steps to deal with complex requirements
2022-07-02 23:57:00 【An ice cream】
Throttling definition
Some frequently operated events will affect performance ," throttle " Used to control the response time interval , When the event triggers , The corresponding function does not trigger immediately , But at specific intervals , Whenever the response interval for execution is reached , Will execute the response function .
Throttling cases
In online games " Aircraft battle ", Keyboard keys can be used to fire bullets , Hit the keyboard quickly and constantly , The plane will not keep launching , But at certain intervals , To control the distance between bullets . For example, the system is set to fire bullets every second , So even if you hit it in a second 20 Secondary keyboard , Still only send 1 Secondary bullet .
Throttling usage scenario
In the process of programming , Many scenes can be used " throttle ".
- Input box frequently 、 Search for
- Click the button frequently 、 Submission of information , Triggering event
- Listen for browser scrolling Events
- Listen for browser zoom events
When throttling is not used
Here simulate a product search box , We need to call the interface to query the content entered by the user , To give users search tips .
When anti shake is not used , We will directly bind the function to the corresponding event .
// html
<input />
// js Code
const inputEl = document.querySelector("input");
let count = 0;
function inputEvent(event) {
console.log(`${
++count} Time input , The content obtained is :${
event?.target?.value}`);
}
inputEl.oninput = inputEvent;
input Enter... In the box "javascriptcsses6", altogether 16 Characters , So the method calls 16 Time

The performance of this method is very low , Because every time you input a character, you call the interface , The pressure on the server is great ," throttle " To execute the function at a specified time , Avoid the waste of resources caused by multiple implementations .
Self defined throttling function
The principle of throttling function implementation is , Execute the function at the specified time interval .
First step : Basic throttling implementation
Determine the time interval between the current and the last execution of the function , If the specified time interval is exceeded , Just execute the function .
function throttle(fn, interval) {
// Set the initial time as 0
let startTime = 0;
const _throttle = function () {
// Get the current time
let currentTime = new Date().getTime();
// Get the time left ( The distance between the current time and the specified interval )
let restTime = interval - (currentTime - startTime);
// The remaining time is less than or equal to 0 when , Execute function
if (restTime <= 0) {
// Execute the passed in function
fn();
// Assign the current time to the initial time
startTime = currentTime;
}
};
return _throttle;
}
inputEl.oninput = throttle(inputEvent, 2000);
The time interval specified here is 2 Second , namely 2 Execute the function once per second .

But then we found that , Parameters are not passed , actually this The direction of is also wrong
The second step : expand this And parameters
adopt apply Methods to change this The direction of , And passing parameters
function throttle(fn, interval) {
// Set the initial time as 0
let startTime = 0;
const _throttle = function (...args) {
// Get the current time
let currentTime = new Date().getTime();
// Get the time left ( The distance between the current time and the specified interval )
let restTime = interval - (currentTime - startTime);
// The remaining time is less than or equal to 0 when , Execute function
if (restTime <= 0) {
// adopt apply change this Point and pass parameters
fn.apply(this, args);
// Assign the current time to the initial time
startTime = currentTime;
}
};
return _throttle;
}
here this And parameters can be obtained ~

So far , Most usage scenarios of throttling have been implemented , The following functions will be more complex .
The third step : The function is executed immediately
In the above function definition , When entering the first character , The function will execute with high probability , Because the time of inputting the first character minus the initialization time 0 Second , Generally, it will be greater than the set time interval .
If you feel that the function execution when entering the first character is unnecessary , Then you can customize the parameters , To control whether the function will execute immediately .
Parameters leading The control function executes immediately , The default is true.
function throttle(fn, interval, options = {
}) {
let startTime = 0;
// leading The default value is true
const {
leading = true } = options ;
const _throttle = function (...args) {
let currentTime = new Date().getTime();
// When immediate execution is not required , Set the initial value to 0 Of startTime Change to current time
if (!leading && !startTime) {
startTime = currentTime;
}
let restTime = interval - (currentTime - startTime);
if (restTime <= 0) {
fn.apply(this, args);
startTime = currentTime;
}
};
return _throttle;
}
// Pass in leading Parameters
inputEl.oninput = throttle(inputEvent, 2000, {
leading: false,
});
This will wait 2s Will execute the first function call

Step four : The function is executed for the last time
" throttle " It is only related to the interval of the function , It has nothing to do with the completion of the last character input .
So when the last character is input , If the time interval with the last function call does not reach the specified time interval , At this time, the function will not be executed . If it is necessary to carry out , You need custom parameters to control function execution .
Through parameters trailing The last execution of the control function , The default is false. When the function needs to be executed at the end , Set the timer before the execution of each time interval , Wait until the interval executes the function , Clear timer , If the last character has not reached the specified interval after input , Then execute the contents in the timer .
function throttle(fn, interval, options = {
}) {
let startTime = 0;
// Set a timer
let timer = null;
// leading The default value is true,trailing The default value is false
const {
leading = true, trailing = false } = options;
const _throttle = function (...args) {
let currentTime = new Date().getTime();
// When immediate execution is not required , Set the initial value to 0 Of startTime Change to current time
if (!leading && !startTime) {
startTime = currentTime;
}
let restTime = interval - (currentTime - startTime);
if (restTime <= 0) {
// When there is a timer , Clear timer
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(this, args);
startTime = currentTime;
// When the execution is completed, the following timer code will not be executed , Avoid repetition
return;
}
// If the last execution is required
if (trailing && !timer) {
// Set timer
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
// When immediate execution is required , The start time is assigned to the current time , conversely , The assignment is 0
startTime = !leading ? 0 : new Date().getTime();
}, restTime);
}
};
return _throttle;
}
// Pass in leading、trailing Parameters
inputEl.oninput = throttle(inputEvent, 2000, {
leading: false,
trailing: true,
});
At this point, the last character is entered , Wait for the interval set in the timer (restTime), The function will execute again .

Step five : Cancel the function
There may be such a scenario , When the user searches, he clicks cancel , Or close the page , At this point, there is no need to send requests .
We add a cancel button , Click to terminate the operation .
// html
<input />
<button> Cancel </button>
// javascript
function throttle(fn, interval, options = {
}) {
let startTime = 0;
// Set a timer
let timer = null;
// leading The default value is true,trailing The default value is false
const {
leading = true, trailing = false } = options;
const _throttle = function (...args) {
let currentTime = new Date().getTime();
// When immediate execution is not required , Set the initial value to 0 Of startTime Change to current time
if (!leading && !startTime) {
startTime = currentTime;
}
let restTime = interval - (currentTime - startTime);
if (restTime <= 0) {
// When there is a timer , Clear timer
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(this, args);
startTime = currentTime;
// When the execution is completed, the following timer code will not be executed , Avoid repetition
return;
}
// If the last execution is required
if (trailing && !timer) {
// Set timer
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
// When immediate execution is required , The start time is assigned to the current time , conversely , The assignment is 0
startTime = !leading ? 0 : new Date().getTime();
}, restTime);
}
};
// Define a cancellation method on the function object
_throttle.cancel = function () {
// When there is a timer , Empty
if (timer) {
clearTimeout(timer);
timer = null;
// Reset start time
startTime = 0;
}
};
return _throttle;
}
// obtain dom Elements
const inputEl = document.querySelector("input");
const cancelBtn = document.querySelector("button");
const _throttle = throttle(inputEvent, 2000, {
leading: false,
trailing: true,
});
// The binding event
inputEl.oninput = _throttle;
cancelBtn.onclick = _throttle.cancel;
When you click Cancel , The contents of the timer will no longer be executed

Step six : Function return value
above " throttle " After the function is executed, there is no return value , If you need to return a value , There are two forms .
Callback function
Pass the form of callback function in the parameter , To get the return value .
function throttle(fn, interval, options = {
}) {
let startTime = 0;
// Set a timer
let timer = null;
// leading The default value is true,trailing The default value is false, The incoming callback function is used to receive the return value
const {
leading = true, trailing = false, callbackFn } = options;
const _throttle = function (...args) {
let currentTime = new Date().getTime();
// When immediate execution is not required , Set the initial value to 0 Of startTime Change to current time
if (!leading && !startTime) {
startTime = currentTime;
}
let restTime = interval - (currentTime - startTime);
if (restTime <= 0) {
// When there is a timer , Clear timer
if (timer) {
clearTimeout(timer);
timer = null;
}
// Get the result of executing the function
const result = fn.apply(this, args);
// Execute the incoming callback function
if (callbackFn) callbackFn(result);
startTime = currentTime;
// When the execution is completed, the following timer code will not be executed , Avoid repetition
return;
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null;
// Get the result of executing the function
const result = fn.apply(this, args);
// Execute the incoming callback function
if (callbackFn) callbackFn(result);
// When immediate execution is required , The start time is assigned to the current time , conversely , The assignment is 0
startTime = !leading ? 0 : new Date().getTime();
}, restTime);
}
};
// Define a cancellation method on the function object
_throttle.cancel = function () {
if (timer) {
// When there is a timer , Empty
clearTimeout(timer);
timer = null;
// Reset start time
startTime = 0;
}
};
return _throttle;
}
const inputEl = document.querySelector("input");
const cancelBtn = document.querySelector("button");
// The incoming callback function is used to receive the return value
const _throttle = throttle(inputEvent, 2000, {
leading: false,
trailing: true,
callbackFn: (value) => {
console.log(" Get the return value ", value);
},
});
inputEl.oninput = _throttle;
cancelBtn.onclick = _throttle.cancel;
Every time the response function is executed , The callback function will be executed once .

promise
By returning promise To get the return value
function throttle(fn, interval, options = {
}) {
let startTime = 0;
// Set a timer
let timer = null;
// leading The default value is true,trailing The default value is false
const {
leading = true, trailing = false } = options;
const _throttle = function (...args) {
// adopt promise To return results
return new Promise((resolve, reject) => {
let currentTime = new Date().getTime();
// When immediate execution is not required , Set the initial value to 0 Of startTime Change to current time
if (!leading && !startTime) {
startTime = currentTime;
}
let restTime = interval - (currentTime - startTime);
if (restTime <= 0) {
// When there is a timer , Clear timer
if (timer) {
clearTimeout(timer);
timer = null;
}
// Get the result of executing the function
const result = fn.apply(this, args);
// adopt resolve Return a successful response
resolve(result);
startTime = currentTime;
return;
}
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null;
// Get the result of executing the function
const result = fn.apply(this, args);
// adopt resolve Return a successful response
resolve(result);
// When immediate execution is required , The start time is assigned to the current time , conversely , The assignment is 0
startTime = !leading ? 0 : new Date().getTime();
}, restTime);
}
});
};
// Define a cancellation method on the function object
_throttle.cancel = function () {
if (timer) {
// When there is a timer , Empty
clearTimeout(timer);
timer = null;
// Reset start time
startTime = 0;
}
};
return _throttle;
}
// obtain dom Elements
const inputEl = document.querySelector("input");
const cancelBtn = document.querySelector("button");
const _throttle = throttle(inputEvent, 2000, {
leading: false,
trailing: true,
});
// apply Is used to this Point to input Elements
const promiseCallback = function (...args) {
_throttle.apply(inputEl, args).then((res) => {
console.log("promise Callback ", res);
});
};
// The binding event
inputEl.oninput = promiseCallback;
cancelBtn.onclick = _throttle.cancel;
promise call then Method gets the return value

Use throttling function in development to optimize the performance of the project , You can customize as above , You can also use third-party libraries .
About anti shake function , You can refer to this article , Custom anti shake function five steps to deal with complex requirements
The above is related to the anti shake function , About js senior , There are many things that developers need to master , You can look at other blog posts I wrote , Ongoing update ~
边栏推荐
- 【STL源码剖析】仿函数(待补充)
- Maybe you read a fake Tianlong eight
- Practical series - free commercial video material library
- List of major chip Enterprises
- Create an interactive experience of popular games, and learn about the real-time voice of paileyun unity
- 判断二叉树是否为满二叉树
- [live broadcast appointment] database obcp certification comprehensive upgrade open class
- 返回二叉树两个节点间的最大距离
- 采用VNC Viewer方式远程连接树莓派
- MATLAB signal processing [Q & a notes-1]
猜你喜欢

MySQL Foundation

来自数砖大佬的 130页 PPT 深入介绍 Apache Spark 3.2 & 3.3 新功能

【ML】李宏毅三:梯度下降&分类(高斯分布)

List of major chip Enterprises

How much do you know about synchronized?

Mapper代理开发

基于OpenCV实现口罩识别

Pytorch里面多任务Loss是加起来还是分别backward?
![[ml] Li Hongyi III: gradient descent & Classification (Gaussian distribution)](/img/75/3f6203410dd2754e578e0baaaa9aef.png)
[ml] Li Hongyi III: gradient descent & Classification (Gaussian distribution)

非路由组件之头部组件和底部组件书写
随机推荐
Why can't the start method be called repeatedly? But the run method can?
Mapper agent development
JDBC练习案例
I've been interviewed. The starting salary is 16K
Sourcetree details
基于OpenCV实现口罩识别
What experience is there only one test in the company? Listen to what they say
采用VNC Viewer方式远程连接树莓派
带角度的检测框 | 校准的深度特征用于目标检测(附实现源码)
Interface difference test - diffy tool
采用VNC Viewer方式遠程連接樹莓派
返回二叉树两个节点间的最大距离
PHP get real IP
Installing redis under Linux
Interface switching based on pyqt5 toolbar button -2
The privatization deployment of SaaS services is the most efficient | cloud efficiency engineer points north
C MVC creates a view to get rid of the influence of layout
PR FAQ, what about PR preview video card?
Bean加载控制
SharedPreferences save list < bean > to local and solve com google. gson. internal. Linkedtreemap cannot be cast to exception