防抖和节流都是防止函数过于频繁调用,但是又有所区别。防抖是短时间内只触发一次;节流是每隔一定的时间触发一次。
防抖
防抖是短时间内只触发一次,输入结束或者暂停的时候触发这个事件
应用场景
- 输入框发送变化的时候,监听onchange事件
- 监听键盘的keyup事件
自定义防抖函数
- 简单版本
function debounce(func, wait) {
let timeout
return function () {
let context = this
let args = arguments
clearTimeout(timeout)
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
- 使用箭头函数
function debounce(fn, wait) {
let timeout
return function (event) {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn.call(this, event)
}, wait);
}
}
- 增加一开始执行还是结束执行的选择
//加上是否立即执行的判断
function debounce3(func, wait, immediate) {
let timeout
return function () {
let context = this
let args = arguments
clearTimeout(timeout)
if (immediate) {
let callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait);
if (callNow) func.apply(context, args)
} else {
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
}
节流
如果持续触发事件,每隔一段时间只执行一次事件
应用场景
- scroll事件滚动触发
- 搜索框输入查询
- 表单验证
- 浏览器的的窗口缩放:resize事件
节流的两种方式
- 时间戳
//使用时间戳,一开始进入就执行,结束之后不会再有一次执行
function throttle(func, wait) {
let old = 0;
let args
return function () {
args = arguments
let now = Date.now()
if (now - old > wait) {
func.apply(this, args)
old = now
}
}
}
- 定时器
//使用定时器 第一次不会触发,最后一次会触发
function throttle1(func, wait) {
let args, timeout
return function () {
args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(this, args)
}, wait);
}
}
}
- 时间戳和定时器结合
//开始立即执行,结束之后过了wait的时间还会再执行一次
function throttle2(func, wait) {
let old = 0
let args, timeout
return function () {
args = arguments
let now = Data.now()
//只负责在刚一进来执行一次
if (now - old > wait) {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
fucn.apply(this, arguments)
old = now
}
if (!timeout) {
timeout = setTimeout(() => {
old = Date.now()
timeout = null
func.apply(this, arguments)
}, wait);
}
}
}