1. 引入场景
- 监听浏览器滚动条的位置,会发现这个函数的执行频率太高了。
- 函数防抖和节流,都是控制事件触发频率的方法。应用场景有很多,输入框持续输入,将输入内容远程校验、多次触发点击事件、onScroll等等。
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
window.onscroll = showTop
2. 防抖(debounce)
1. 思路: 在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
- 如果在200ms内没有再次触发滚动事件,那么就执行函数
- 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
可以理解为:比如送外卖,接到一单后,开始计时,如果5分钟内又收到一单,就重新计时5分钟。直到5分钟没有收到信订单,再送货。
2. 代码
防抖重在清零 clearTimeout(timer)
// 防抖函数
function debounce(fn, delay){
let timer = null // timer计时,闭包,不会被外界修改
return function() {
if (timer) { // 如果已经开始计时了,就清除计时
clearTimeout(timer)
}
// 重新开始计时,delay后执行函数,然后将定时器清空
timer = setTimeout(()=>{
fn.apply(this,arguments)
//清空定时器
timer = null
},delay)
}
}
// fn
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
// 使用
input1.addEventListener('keyup', debounce(function (e) {
console.log(e.target)
console.log(input1.value)
}, 600))
// 使用防抖
window.onscroll = debounce(showTop,1000)
对于短时间内连续触发的事件(上面的滚动事件),防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。
4. 应用
- 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖
- 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖
- 文本编辑器实时保存,当无任何更改操作一秒后进行保存
3. 节流(throttle)
- 用防抖的方案的结果是:用户如果不断触发,就永远不会执行。
- 我们想即使用户不断触发,也能在某个时间间隔给出反馈。
- 所以引入了节流
1. 思路
类似阀门一样,定期开发,就是函数执行一次后,在一个时间段内失效,过了这段时间才能再次执行。定期触发。
2. 代码
节流重在开关锁 timer有效无效,如果timer存在,则想象为在冷冻期内,什么也不做。
function throttle(fn, delay = 100) {
let timer = null
return function () {
if (timer) { //如果在定时器内,就什么也不做,返回
return
}
timer = setTimeout(() => {
fn.apply(this, arguments) // 调用函数,清空定时器
timer = null
}, delay)
}
}
// 以下照旧
function showTop () {
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
console.log('滚动条位置:' + scrollTop);
}
//
div1.addEventListener('drag', throttle(function (e) {
console.log(e.offsetX, e.offsetY)
}))
window.onscroll = throttle(showTop,1000)
3. 应用
- scroll 事件,每隔一秒计算一次位置信息等
- 浏览器播放事件,每个一秒计算一次进度信息等
- input 框实时搜索并发送请求展示下拉列表,没隔一秒发送一次请求 (也可做防抖)