防抖
原理
事件响应函数在一段时间后才执行,如果在这段时间内再次调用,则重新计算执行时间;当预定的时间内没有再次调用该函数,则执行该事件响应函数。
// 这里用代码解释一下,如果不用防抖let count = 0// 演示事件是如何频繁发生的const container = document.querySelector('#container')container.onmousemove = doSomeThing // 事件响应函数function doSomeThing() {container.innerHTML = count++// 如果有ajax请求,也会一直请求并向后端发送}
如果不用防抖,那么只要鼠标在container区域移动,就会一直触发事件响应函数doSomeThing,如果在事件响应函数里面是执行ajax请求,那么就意味着只要鼠标移动,就会不停地向服务器发送ajax请求,容易导致服务器崩溃,所以我们会用到防抖。
// 完成简单的防抖(鼠标不停地移动时不会触发doSomeThing事件,当鼠标停下时才会触发)let count = 0const container = document.querySelector('#container')// 鼠标移动响应事件,直接调用防抖函数container.onmousemove = debounce(doSomeThing, 300) function doSomeThing() {// 这里的this是指向window的,如果需要用this,就比较麻烦container.innerHTML = count++}// 防抖函数function debounce(func,wait){let timeoutreturn function() {timeout && clearTimeout(timeout)timeout = setTimeout(() => {func()}, wait)}}
// 完善防抖功能
// func:事件响应函数
// wait:时间间隔
// immediate:是否立即执行
function debounce(func, wait, immediate){let timeoutreturn function() { let context = this // this指向container容器,将其保存下来let args = arguments // arguments中有鼠标事件(Event对象)clearTimeout(timeout)if(immediate) { // 立即执行,就是在鼠标滑动会立即执行,不等await时间间隔,但是在鼠标不停的滑动时不会执行,而是// 在鼠标停下来的那一刻,马上执行,不再等await时间let callNow = !timeout // 在鼠标不停地滑动过程中,timeout是有值的,所有callNow为false,就不会执行func函数timeout = setTimeout(() => {timeout = null}, wait)// 立即执行if(callNow) func.apply(context, args)} else {// 不会立即执行timeout = setTimeout(function() {// console.log(this) // 内部函数 this是指向 window 的// console.log(context) // 所以要用外部函数的 this(container)func.apply(context, args) // context.func() ->this.func()}, wait)} }
}let count = 0
const container = document.querySelector('#container')function doSomeThing(e) {// 改变内部函数 this 的指向// console.log(this) // this 本来指向 window// debounce中通过外部函数调用doSomeThing方法后,这里的this就指向了container// event指向问题console.log(e) // 将 event对象传到该函数中// 可能会做回调或者ajax请求container.innerHTML = count++
}// 防抖
container.onmousemove = debounce(doSomeThing, 300, true)
防抖的应用场景
1.scroll事件滚动触发
2.搜索框输入查询
3.表单验证
4.按钮提交事件
5.浏览器窗口缩放,resize事件