场景
在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。
因频繁执行DOM操作,资源加载等行为,导致UI停顿甚至浏览器崩溃。
- window对象频繁的onresize,onscroll等事件
- 拖拽的mousemove事件
- 射击游戏的mousedown,keydown事件
- input文字输入,自动完成的keyup事件
防抖
函数防抖:将几次操作合并为一此操作进行。原理是维护一个计时器,规定在等待时间后触发函数,但是在等待时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。好多文章的例子考虑了防抖节流函数存在参数的情况,但并没有传入参数。下面我们上一个完整版代码。 持续触发click事件时,并不执行fangdouFn函数,当1000毫秒内没有触发click事件时,才会延时触发click事件。
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>防抖</title>
</head>
<body>
<div id="fang" style="height: 200px; width: 200px; background: #73DE80"></div>
</body>
<script>
var fangId = document.getElementById('fang')
var testFD = fangdou(fangdouFn,1000)
fangId.addEventListener('click', function (e){testFD(e)})
function fangdou(fn,wait = 500) {
let time
return function () {
if(time){
clearTimeout(time)
}
time = setTimeout(()=>{
fn.apply(this,arguments)
},wait)
}
}
function fangdouFn(e) {
console.log(123,e)
}
</script>
</html>
如果函数不传参数的话,可以直接这么写
var fangId = document.getElementById('fang')
fangId.addEventListener('click', fangdou(fangdouFn,1000))
function fangdou(fn,wait = 500) {
let time
return function () {
if(time){
clearTimeout(time)
}
time = setTimeout(()=>{
fn.apply(this,arguments)
},wait)
}
}
function fangdouFn() {
console.log(123)
}
节流
函数节流:使得一定时间内只触发一次函数。原理是通过一个标志位,用这个标志位判断函数知否执行,只有规定时间内函数执行之后,标志位改变状态才能进行下一次函数执行。
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>节流</title>
</head>
<body>
<div id="fang" style="height: 200px; width: 200px; background: #73DE80"></div>
</body>
<script>
var fangId = document.getElementById('fang')
var testFD = jieliu(jieliuFn,1000)
fangId.addEventListener('click', function (e){testFD(e)})
function jieliu(fn,wait = 500) {
let time = true
return function () {
if(time){
time = false
setTimeout(()=>{
time = true
fn.apply(this,arguments)
},wait)
}
}
}
function jieliuFn(e) {
console.log(123,e)
}
</script>
</html>