Anti-shake and throttling (Xiaobai learns anti-shake and throttling)

Why use anti-shake and throttling?

During development, we often encounter events that need to be triggered frequently, such as the viewport size change of the window object, scrolling (resize, scroll), mouse movement events (mousedown, mousemove, etc.), and the keyboard press and pop-up event of the form label (keydown, keyup) and so on;

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<input type="text" name="" id="" value="" />
	</body>
	<script type="text/javascript">
		document.querySelector("input").addEventListener("keyup", e => {
			console.log(e.target.value)
		})
	</script>
</html>

 

 For another example, we need to request data after an event is triggered. Such a multi-frequency request for data is obviously not desirable. In order to avoid frequent triggering of similar events, we can use anti-shake and throttling.

Anti-shake

principle:

The callback function is executed n seconds after the event is triggered. If the event is triggered again within n seconds, the time will be re-timed, which is essentially a closure. The result is to merge frequently triggered events into one and execute them at the end.

Code:

Initial realization:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<input type="text" name="" id="" value="" />
	</body>
	<script type="text/javascript">
		
		function debounce(callback,wait){
			let timer;
			console.log(this)
			return () => {
				clearTimeout(timer);
				timer = setTimeout(() => {
					callback()
				},wait)
			}
		}
		
		function callback(){
			console.log('回调函数执行了');
		}
		
		document.querySelector("input").addEventListener("keyup",debounce(callback,1000))
		
	</script>
</html>

However, in development, it is almost always necessary to obtain information from the target node to perform callbacks, such as entering a user name to query the user, and obtaining the entered user name to send a request query. You can use apply ( detailed explanation of apply ) to change the this point of the callback function to obtain node information, and pass the event object of the target node to the callback function through the argument set (arguments) to ensure that the event is also available in the callback function Object operation.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<input type="text" name="" id="" value="" />
	</body>
	<script type="text/javascript">
		
		function debounce(callback,wait){
			let timer;
			return function(){
				clearTimeout(timer);
				timer = setTimeout(() => {
					callback.apply(this,arguments)
				},wait)
			}
		}
		
		function callback(e){
			console.log('回调函数执行了');
			console.log(e);
			console.log(this);
		}
		
		document.querySelector("input").addEventListener("keyup",debounce(callback,1000))
		
	</script>
</html>

Is this perfect? No, no. If some requirements are to execute the callback function immediately after the event is triggered, such as scroll loading, the callback will be executed immediately after the bottom is reached.

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<input type="text" name="" id="" value="" />
	</body>
	<script type="text/javascript">
		
		function debounce(callback,wait,immediate){
			let timer;
			return function(){
				clearTimeout(timer);
				if(immediate){
					let callNow = !timer;
					timer = setTimeout(() => {
						timer = null;
					},wait)
					//立即执行
					if(callNow) callback.apply(this,arguments);
				}else{
					timer = setTimeout(() => {
						callback.apply(this,arguments)
					},wait)
				}
				
				
			}
		}
		
		function callback(e){
			console.log('回调函数执行了');
			console.log(e);
			console.log(this);
		}
		
		document.querySelector("input").addEventListener("keyup",debounce(callback,2000,true))
		
	</script>
</html>

 

The last is to add and cancel the anti-shake function:

function debounce(callback,wait,immediate){
	let timer;
	return function(){
		clearTimeout(timer);
		if(immediate){
			let callNow = !timer;
			timer = setTimeout(() => {
				timer = null;
			},wait)
			//立即执行
			if(callNow) result = callback.apply(this,arguments);
		}else{
			timer = setTimeout(() => {
				callback.apply(this,arguments)
			},wait)
		}
	}
	debounce.cancel = () => {
		clearTimeout(timer);
		timer = null
	}
}

That's it for anti-shake, let's talk about throttling.

Throttling

principle:

In frequently triggered events, the callback function is executed once every n seconds.

Code:

There are two ways to achieve throttling, using time difference and timer.

	// 时间差实现
	function throttle(callback, wait) {
		let oldtime = 0;
		return function() {
			let now = new Date().getTime();
			if (now - oldtime > wait) {
				callback();
				oldtime = now
			}
		}
	}
	// 定时器实现
	function throttleTimeOut(callback, wait) {
		let timeOut;
		return function() {
			if(!timeOut){
				timeOut = setTimeout(() => {
					timeOut = null;
					callback.apply(this,arguments);
				},wait)
			}
		}
	}
	function fn(e) {
		console.log(this.value)
		console.log(e);
	}
	document.querySelector("input").addEventListener("keyup", throttleTimeOut(fn, 1000))

The throttling achieved by the two methods, the throttling achieved by the time difference is executed immediately and the last time is not executed (regardless of the head and the end), and the timer is not executed immediately, and the last time is executed (the tail and the head are ignored); both Combine it to get the throttling function of the head and the tail of Gu:

	function throttle(callback, wait) {
		let timeOut;
		let oldtime = 0;
		return function() {
			
			let now = new Date().getTime();
			if (now - oldtime > wait) {
				if(timeOut){
					clearTimeout(timeOut);
					timeOut = null;
				}
				callback.apply(this,arguments);
				oldtime = now
			}
			
			if(!timeOut){
				timeOut = setTimeout(() => {
					oldtime = new Date().getTime()
					timeOut = null;
					callback.apply(this,arguments);
				},wait)
			}
			
			
		}
	}

 

Reference blog: js anti-shake practical explanation

Guess you like

Origin blog.csdn.net/m0_43599959/article/details/114777356