防抖和节流函数的实现
首先我们需要对防抖和节流函数作一个概念的区别:因为这两者是不同的一个概念
一、防抖和节流函数的基本认识
- 1.防抖函数
防抖函数相当于是对触发的数据做一个延迟处理。比如我们平时在使用搜索框时,我们一输入内容就会发送对应的网络请求,如果我们后面一直有在输入内容,那么就会一直发送网络请求。正确的做法应该是在我们输入期间不发送网络请求,当我们输入完成后在发送网络请求。 - 2.节流函数
节流函数相当于是我们在一个时间段内一直频繁的触发数据请求,但是数据的请求还是根据设定的一个频率来进行响应的。比如我们在玩LOL游戏时,当需要回城时,我们触发回城按钮,进入到回城状态进会有一个等待的时间,如果在这个等待时间内有重复去执行回城按钮,这时回城状态并不会做出其他响应,而是等时间到了后才会完成回城。这也说明了,在我们回城的过程中,一直触发回城按钮都是不会响应的,他会按照自己的一个回城时间才做出响应。 - 3.防抖函数和节流函数的区别
区别:
防抖函数,是将一段时间内频繁被执行的数据,延迟到后面一次性做一个执行
节流函数,在触发了数据的请求后 ,当数据还没有响应时,在这段时间内无论重复执行多少次,都还是会执行设置数据响应的频率来执行的。也就是说设定的频率为10秒执行一次,那么无论在10内触发了多少次,过10秒后还是只会执行一次。
二、防抖函数的基本实现
代码如下(示例):
//创建一个防抖函数debounce
function debounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
// 2.真正执行的函数
const _debounce = function () {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn()
}, delay)
}
return _debounce
}
版本二:this和参数实现
//创建一个防抖函数debounce
function debounce(fn, delay) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
// 2.真正执行的函数
const _debounce = function (...ages) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
//因为这里是箭头函数,所以指向上层作用域,然后把参数给fn函数传递过去
//因为参数可能不只一个所以使用展开语法。
fn.apply(this, ages)
}, delay)
}
return _debounce
}
版本三:立即执行
//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
let isInvoke = false
// 2.真正执行的函数
const _debounce = function (...ages) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, ages)
isInvoke = true
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, ages)
isInvoke = false
}, delay)
}
}
return _debounce
}
版本四:取消功能
//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
let isInvoke = false
// 2.真正执行的函数
const _debounce = function (...ages) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
fn.apply(this, ages)
isInvoke = true
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
fn.apply(this, ages)
isInvoke = false
}, delay)
}
}
//_debounce是一个函数,函数也可以做为是一个对象,所以我们可以给他添加方法
_debounce.cancel = function () {
//删除要执行的函数
if (timer) clearTimeout(timer)
//把所有属性都恢复成默认值
timer = null
isInvoke = false
}
return _debounce
}
版本五:函数的返回值
//创建一个防抖函数debounce
function debounce(fn, delay, immediate = false, resultCallback) {
// 1.定义一个定时器, 保存上一次的定时器
let timer = null
let isInvoke = false
// 2.真正执行的函数
const _debounce = function (...ages) {
// 取消上一次的定时器
if (timer) clearTimeout(timer)
// 判断是否需要立即执行
if (immediate && !isInvoke) {
const result = fn.apply(this, ages)
isInvoke = true
resultCallback(result)
} else {
// 延迟执行
timer = setTimeout(() => {
// 外部传入的真正要执行的函数
const result = fn.apply(this, ages)
resultCallback(result)
isInvoke = false
}, delay)
}
}
//_debounce是一个函数,函数也可以做为是一个对象,所以我们可以给他添加方法
_debounce.cancel = function () {
if (timer) clearTimeout(timer)
timer = null
isInvoke = false
}
return _debounce
}
这里函数的返回值是通过传入的回调函数来实现,也可能通过返回一个Promise来完成
三、节流函数的基本实现
function throttle(fn, interval) {
// 1.记录上一次的开始时间
let lastTime = 0
// 2.事件触发时, 真正执行的函数
const _throttle = function () {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
}
}
return _throttle
}
版本二:leading 和trailing 的实现
function throttle(fn, interval, options = { leading: true, trailing: false }) {
// 1.记录上一次的开始时间
const { leading, trailing } = options
let lastTime = 0
let timer = null
// 2.事件触发时, 真正执行的函数
const _throttle = function (...args) {
// 2.1.获取当前事件触发时的时间
const nowTime = new Date().getTime()
if (!lastTime && !leading) lastTime = nowTime
// 2.2.使用当前触发的时间和之前的时间间隔以及上一次开始的时间, 计算出还剩余多长事件需要去触发函数
const remainTime = interval - (nowTime - lastTime)
if (remainTime <= 0) {
//进入到这我们肯定会调用函数的,所以需要防止重复调用
if (timer) {
clearTimeout(timer)
timer = null
}
// 2.3.真正触发函数
fn()
// 2.4.保留上次触发的时间
lastTime = nowTime
return
}
//判断是否需要执行最后一次输出
if (trailing && !timer) {
timer = setTimeout(() => {
timer = null
//防止我们延迟调用函数时,上面时间到了后,又重复调用
lastTime = !leading ? 0 : new Date().getTime()
fn()
}, remainTime)
}
}
return _throttle
}
版本三this和参数实现
版本四取消功能
版本五函数的返回值
上面这三这个功能基本上是和节流函数中实现的没有差别,节流函数的重点就是leading和trailing的实现。所以重复的代码就不展示了。查看防抖函数上实现的功能即可。
总结
上述代码为防抖和节流函数的基本实现过程,和一些库里面的防抖节流函数差不多。但是想自己实现节流防抖函数的可以参数本文中的代码来实现一下。