节流与防抖,以及自身体会
节流
在前端页面中存在着很多高频事件,如:浏览器的滚动事件,输入框实时校验等。如果不做处理,一定程度上会影响性能。
节流:函数执行之后,在规定的时间内不再触发。其实现思路如下:
- 记录上一次函数执行完毕的时间,初始化为0
- 记录本次开始执行函数前的时间
- 这两次时间相减,如果大于规定的时间就执行,反之不执行
function throttle(fn, delay) {
// 上一次执行函数执行完的时间
var lasttime = 0
// 当前这次开始i 执行函数前的时间
var now = Date.now()
if(now - lasttime > delay) {
fn()
lasttime = Date.now()
}
}
document.body.onscroll = function() {
throttle(function(){console.log('scroll')}, 300)
}
按照上诉思路写下来会出现一个问题
- 每次滚动都会初始化lasttime。(所以需要保存变量lasttime)
function throttle(fn, delay) {
// 上一次执行函数执行完的时间
var lasttime = 0
return function() {
// 当前这次开始i 执行函数前的时间
var now = Date.now()
if(now - lasttime > delay) {
fn()
// 重置时间
lasttime = Date.now()
}
}
}
// 绑定一个滚动触发的事件
document.body.onscroll = throttle(function() {
console.log('scroll-->', Date.now())
}, 300)
- 使用闭包保存上一次执行完毕的时间
- 运行结果可以发现,相邻两次输出的时间指差大于300
防抖
防抖:一个需要高高频触发的函数,在规定的时间内,只让最后一次生效,前面的不生效
这个功能通常用于防止用户猛烈点击表单提交按钮。
知道定义之后,大概的实现思路:
- 使用定时器
- 保存上一次的定时器对象
- 不停的清除上一次定时器对象,只保留最后一次的定时器对象
function debounce(fn, delay){
var timer = null
return function() {
// 不停的清除定时器 保留最后一次的定时器
// 清楚上一次的timer
clearTimeout(timer)
timer = setTimeout(function() {
fn()
}, delay)
}
}
document.getElementById('btn').addEventListener('click', debounce(function(){
console.log('click')
}, 300))
以上也使用了闭包来保存了上一次的定时器对象。
对于delay的设定需要谨慎。如果我们上一次点击按钮与当前只一次点击按钮的时间之差小于delay,那么上一次的定时器就会被清除,重新启动一次定时器。在delay的延迟之后执行函数。所以如果delay的数值如果设置过长,延迟就越长。
节流与防抖的区别
假如我们都用节流与防抖来做输入框的实时校验。
对于节流来说:
- 输入框第一次输入的时候就回去校验。
- 然后然后在规定时间内不再去触发。
- 如果最后一次与倒数第二次的时间间隔小于delay,最后一次不等去校验。
- 从上面可以看得出来,用节流做输入框校验有一定的风险
对于防抖:
- 开始输入的时候不会马上校验
- 最后一次输入完始终回去校验
- 始终会有delay的延迟。
综上所诉两者有好处也同时存在风险,具体场景做合理的选择。