防抖
防抖原理
- 防抖函数的作用就是控制函数在一定时间内的执行次数。防抖意味着N秒内函数只会被执行一次,如果N秒内再次被触发,则重新计算延迟时间。
防抖的应用场景
- 搜索框输入查询,如果用户一直在输入中,没有必要不停地调用去请求服务端接口,等用户停止输入的时候,再调用,设置一个合适的时间间隔,有效减轻服务端压力。
- 表单验证。
- 按钮提交事件。
- 浏览器窗口缩放,resize事件(如窗口停止改变大小之后重新计算布局)等。
防抖函数实现
function debounce(func, wait, immediate = true) {
let timeout, result
// 延迟执行函数
const later = (context, args) => setTimeout(() => {
timeout = null // 倒计时结束
if(!immediate) {
// 执行回调
result = func.apply(context, args)
context = args = null
}
}, wait)
let debounced = function(...params) {
if(!timeout) {
timeout = later(this, params)
if(immediate) {
// 立即执行
result = func.apply(this, params)
}
} else {
clearTimeout(timeout)
// 函数在每个等待时延的结束被调用
timeout = later(this, params)
}
return result
}
// 提供在外部清空定时器的方法
debounced.cancel = function() {
clearTimeout(timeout)
timeout = null
}
return debounced
}
immediate为true时,表示函数在每个等待时延的开始被调用。immediate为false时,表示函数在每个等待时延的结束被调用。
节流
节流原理
- 节流函数的作用是规定一个单位时间,在这个单位时间内最多只能触发一次函数执行,如果这个单位时间内多次触发函数,只能有一次生效。
节流的应用场景
- 按钮点击事件
- 拖拽事件
- onScoll
- 计算鼠标移动的距离(mousemove)
节流函数实现
function throttle(func, wait, options = {}) {
var timeout, context, args, result
var previous = 0
var later = function() {
previous = options.leading = false ? 0 : (Date.now() || new Date().getTime())
timeout = null
result = func.apply(context, args)
if(!timeout) {
context = args = null
}
}
var throttled = function() {
var now = Date.now() || new Date().getTime()
if(!previous && options.leading === false) {
previous = now
}
// remaining 为距离下次执行 func 的时间
// remaining > wait, 表示客户端系统时间被调整过
var remaining = wait - (now - previous)
context = this
args = arguments
// remaining 小于等于0,表示事件触发的事件间隔大于设置的wait
if(remaining <=0 || remaining > wait) {
if(timeout) {
// 清空定时器
clearTimeout(timeout)
timeout = null
}
// 重置 previous
previous = now
// 执行函数
result = func.apply(context, args)
if(!timeout) {
context = args = null
} else if(!timeout && options.trailing !== false){
timeout = setTimeout(later, remaining)
}
return result
}
}
throttled.cancel = function() {
clearTimeout(timeout)
previous = 0
timeout = context = args = null
}
return throttled
}
禁用第一次首先执行,传递 {leading: false} ;想禁用最后一次执行,传递 {trailing: false}