节流防抖
防抖 (debounce) 与节流 (throttle ) 在实际中会经常使用。这两天仔细看了一下,有点理解了。
防抖 Debounce
含义: 在规定的时间内, 一个事件不管触发多少次, 最终只会执行一次, 在这个时间内, 如果再次被触发, 则会重新计时。即每次触发事件有一个 delay,在这个 delay 时间内,不会再次触发事件,只有 delay 时间后,才会触发事件。 好记一点: 防抖就是防止手抖。比如一个输入框,本意来说输入框的 value 会根据实时输入变化,但是呢,有些人手有问题,在不停地抖抖抖,所以输入框的值就会变化得很快。如果这是一个搜索框,需要实时返回搜索数据,那么请求就会发送很多很多,会对资源造成浪费。
实现
举例说明:
<style>
.conatainer {
width: 100%;
height: 200px;
text-align: center;
line-height: 200px;
color: #fff;
background: #444444;
font-size: 30px;
}
</style>
<div class="container"></div>
<script>
const conainer = document.querySelector('.container')
let count = 1
function getAction(e) {
conainer.innerHTML = count + 1
}
</script>
不防抖
container.onmousemove=getAction
这样的话当我们移动鼠标,container 中的数字会不断变化,也就是说getAction
会触发很多次。
实现防抖
function debounce(fn, delay) {
let timer
return function () {
console.log(this)
clearTimeout(timer)
timer = setTimeout(fn, delay)
}
}
container.onmousemove = debounce(getAction, 1000)
现在移动鼠标到停止移动, getAction
只会在停止后 1s 触发一次。如果要触发第二次只有再次移动鼠标然后停止等 1s。
防抖中的 this
现在防抖已经是成功了,但是还有一个问题:上面的console.log(this)
按照我们的意愿应该打印 container
对象,但是上面打印出了 window。所以还需要进行一下修改:
function debounce(fn, delay) {
let timer
return function () {
let that = this
clearTimeout(timer)
timer = setTimeout(function () {
console.log(that)
fn.apply(that)
}, delay)
}
}
container.onmousemove = debounce(getAction, 1000)
上面的代码暂存了一个this
, 然后传入fn
的apply
方法, 这样在调用时this
的指向就会变成container
对象。
关于
apply
请参阅Function.prototype.apply()
防抖函数的参数(event 对象)
js 在处理事件时, 会传入 evnet 对象;如果使用debounce
函数,会打印 undefined:
function getAction(e) {
console.log(e)
conainer.innerHTML = count + 1
}
container.onmousemove = getAction //打印 event 对象
container.onmousemove = debounce(getAcion, 1000) // 打印undefined
所以,要对防抖函数进行修改,可以传入参数:
function debounce(fn, delay) {
let timer
return function () {
let that = this
let args = arguments
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(that, args)
}, delay)
}
}
arguments
是函数参数的类数组对象,详情请参阅Arguments 对象
节流 Throttle
含义: 在一个时间段内, 一个事件只会触发一次,如果在这个时间段内,事件被触发多次,只有第一次会执行,其余的会被忽略。
实现
举例说明:
<style>
.conatainer {
width: 100%;
height: 200px;
text-align: center;
line-height: 200px;
color: #fff;
background: #444444;
font-size: 30px;
}
</style>
<div class="container"></div>
<script>
const conainer = document.querySelector('.container')
let count = 1
function getAction(e) {
conainer.innerHTML = count + 1
}
</script>
不节流
container.onmousemove = getAction
同上,当我们移动鼠标,container 中的数字会不断变化,也就是说getAction
会触发很多次。
实现节流
function throttle(fn, delay) {
let timer
return function () {
let that = this
let args = arguments
if (timer) {
return
}
timer = setTimeout(function () {
fn.apply(that, args)
timer = null
}, delay)
}
}
container.onmousemove = throttle(getAction, 1000)
当我们一直移动鼠标,container 中的数字会一直变化,但是变化的频率是固定的,1s,也就是说getAction
会触发很多次,但是只有每隔 1s 才会执行一次。