一、什么是防抖和节流
比如搜索框,用户在输入的时候使用change事件去调用搜索,如果用户每一次输入都去搜索的话,那么消耗的服务器资源就太大了。
1.防抖 - debounce
其中一种解决方案就是每次用户停止输入后,延迟超过xxxms时,才去搜索,这就是防抖。
原理:将若干个函数调用合成为一次,并在给定时间过去之后仅被调用一次。
var num = 1
var content = document.getElementById('content')
function count() {
content.innerHTML = num++
}
const debounce = (func, wait) => {
let timer // 维护一个timer,用来记录当前执行函数状态
return function () {
// 通过this 和 arguments 获取函数的作用域和变量
let context = this
var args = arguments
if (timer) {
clearTimeout(timer) // 清理掉正在执行的函数,并重新执行
}
timer = setTimeout(() => {
console.log(context)
func.apply(context, args)
}, wait)
}
}
content.onmousemove = debounce(count, 1000)
debounce函数封装后,返回内部函数
每一次事件被触发,都会清除当前的timer然后重新设置超时并调用。这会导致每一次高频事件都会取消前一次超时调用,导致事件处理程序不能被触发
只有当高频事件停止,最后一次事件触发的超时调用才能在wait时间后执行。
2.节流 - throttle
另一种解决方案比防抖要宽松些,这时我们不想用户一味的输入,而是给用户一些搜索提示,所以在当中限制每过xxxms就查询一次此时的String,这就是节流。
原理:节流函数不管事件触发有多频繁,会被保证在规定时间内一定会执行一次真正的事件处理函数。
代码实现有两种,一种是时间戳,另一种是定时器
1) 时间戳实现:
const throttle = (func, wait) => {
let pre = 0
return function () {
let context = this
let args = arguments
let now = Date.now()
if (now - pre >= wait) {
func.apply(context, args)
pre = Date.now()
}
}
}
当高频事件触发时,第一次会立即执行(给事件绑定函数与真正触发事件的间隔如果大于wait的话),而后再怎么频繁触发事件,也都是会没wait秒才执行一次。而当最后一次事件触发完毕后,事件也不会再被执行了。
2) 定时器实现:
当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行;知道wait秒后,定时器执行执行函数,清空定时器,这样就可以设置值下个定时器。
const throttle = (func, wait) => {
let timer = null
return function () {
let context = this
let args = arguments
if (!timer) {
timer = setTimeout(() => {
func.apply(context, args)
timer = null
}, wait)
}
}
}
当第一次触发事件时,肯定不会立即执行函数,而是在wait秒后才执行。
之后连续不断触发事件,也会每wait秒执行一次。
当最后一次停止触发后,由于定时器的wait延迟,可能还会执行一次函数。
3)综合使用时间戳与定时器,完成一个事件触发时立即执行,触发完毕还能执行一次的节流函数。
function throttle(func, wait, type) {
if (type === 1) {
var previous = 0
} else if (type === 2) {
var timer
}
return function () {
var context = this
var args = arguments
if (type === 1) {
var now = Date.now()
if (now - previous >= wait) {
func.apply(context, args)
previous = now
}
} else if (type === 2) {
if (!timer) {
timer = setTimeout(() => {
timer = null
func.apply(context, args)
}, wait)
}
}
}
}