前几天在项目中看见防止查询屡次点击的一种写法缓存
/** * 相似于一种简单的防抖思想的实现 */
search = () => {
clearTimeout(this.timer);
this.timer = setTimeout(() => {
fetch('url').then((res) => {
//todo
}).catch(() => {
//todo
})
} ,1000);
}
复制代码
可是这样会存在一种问题:app
1.当用户点击一次时,其实所用的时间为接口请求时间加上1秒,当接口响应时间只有几十毫秒时,这种作法就有点鸡肋。函数
2.当用户连续点击10次时,其实前9次请求都被清除掉了(由于咱们连续点击之间的时间间隔确定会小于1秒),只有最后一次点击被执行,可是查询的时间变为了1秒加上接口请求时间fetch
1.当用户点击一次,其实所用的时间为接口请求时间加上50毫秒ui
2.当用户点击10次时,假如说接口请求时间为30毫秒,而用户点击的时间间隔为200毫秒,也就是说当setTimeOut的时间加上接口请求时间小于用户点击的时间间隔时,并无限制住,其实至关于执行10次。this
“其实在项目开发中较经常使用的一种写法时,由于咱们大部分的查询都添加了loading效果,并且loading效果的显示是经过this.state.isLoading来进行判断的,那么这样就好判断了,点击查询时先判断this.state.isLoading是否为false,当为false时,下发请求,为true时,给出正在努力查询中的提示。”搜索引擎
再回顾一下防抖概念:url
你是否在平常开发中遇到一个问题,在滚动事件中须要作个复杂计算或者实现一个按钮的防二次点击操做。这些需求均可以经过函数防抖动来实现。尤为是第一个需求,若是在频繁的事件回调中作复杂计算,颇有可能致使页面卡顿,不如将屡次计算合并为一次计算,只在一个精确点作操做。spa
PS:防抖和节流的做用都是防止函数屡次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于wait,防抖的状况下只会调用一次,而节流的 状况会每隔必定时间(参数wait)调用函数。code
咱们先来看一个袖珍版的防抖理解一下防抖的实现(相似项目中防止查询屡次点击):
// func是用户传入须要防抖的函数
// wait是等待时间
const debounce = (func, wait = 50) => {
// 缓存一个定时器id
let timer = 0
// 这里返回的函数是每次用户实际调用的防抖函数
// 若是已经设定过定时器了就清空上一次的定时器
// 开始一个新的定时器,延迟执行用户传入的方法
return function(...args) {
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
// 不难看出若是用户调用该函数的间隔小于wait的状况下,上一次的时间还未到就被清除了,并不会执行函数
复制代码
实现一个带有当即执行选项的防抖函数
// 这个是用来获取当前时间戳的
function now() {
return +new Date()
}
/** * 防抖函数,返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行 * @param {function} func 回调函数 * @param {number} wait 表示时间窗口的间隔 * @param {boolean} immediate 设置为ture时,是否当即调用函数 * @return {function} 返回客户调用函数 */
function debounce (func, wait = 50, immediate = true) {
let timer, context, args
// 延迟执行函数
const later = () => setTimeout(() => {
// 延迟函数执行完毕,清空缓存的定时器序号
timer = null
// 延迟执行的状况下,函数会在延迟函数中执行
// 使用到以前缓存的参数和上下文
if (!immediate) {
func.apply(context, args)
context = args = null
}
}, wait)
// 这里返回的函数是每次实际调用的函数
return function(...params) {
// 若是没有建立延迟执行函数(later),就建立一个
if (!timer) {
timer = later()
// 若是是当即执行,调用函数
// 不然缓存参数和调用上下文
if (immediate) {
func.apply(this, params)
} else {
context = this
args = params
}
// 若是已有延迟执行函数(later),调用的时候清除原来的并从新设定一个
// 这样作延迟函数会从新计时
} else {
clearTimeout(timer)
timer = later()
}
}
}
复制代码
上面函数的实现思路: