文章目录
- 清理所有定时器
- 防抖代码
- 节流代码
- 自定义
- 时间戳
- 定时器
- 复杂实现
- vueuse中工具类
- 定时任务
- 手动实现
- 工具类useInterval
清理所有定时器
export function clearAllTimer() {let id = setTimeout(() => { }, 0)while (id > 0) {window.clearTimeout(id)id--}
}
防抖代码
当函数绑定一些持续触发的事件如:resize、scroll、mousemove ,键盘输入,多次快速click等等,
如果每次触发都要执行一次函数,会带来性能下降,资源请求太频繁等问题
// 第一个参数是需要进行防抖处理的函数,第二个参数是延迟时间,默认为1秒钟
// 这里多传一个参数,immediate用来决定是否要第一次立即执行, 默认为false
function debounce(fn, delay = 1000, immediate = false, resultCb) {
// 实现防抖函数的核心是使用setTimeout// time变量用于保存setTimeout返回的Idlet time = null// isImmediateInvoke变量用来记录是否立即执行, 默认为falselet isImmediateInvoke = false// 将回调接收的参数保存到args数组中function _debounce(...args) {// 如果time不为0,也就是说有定时器存在,将该定时器清除if (time !== null) {clearTimeout(time)}// 当是第一次触发,并且需要触发第一次事件if (!isImmediateInvoke && immediate) {// 将函数的返回值保存到result中const result = fn.apply(this, args)if (typeof resultCb === 'function') {// 当用户传递了resultCb函数时,执行该函数,并将结果以参数传递出去。resultCb(result)}// 将isImmediateInvoke设置为true,这样不会影响到后面频繁触发的函数调用isImmediateInvoke = true;}time = setTimeout(() => {// 使用apply改变fn的this,同时将参数传递给fnfn.apply(this, args) // 当定时器里的函数执行时,也就是说是频繁触发事件的最后一次事件// 将isImmediateInvoke设置为false,这样下一次的第一次触发事件才能被立即执行isImmediateInvoke = false}, delay)}// 防抖函数会返回另一个函数,该函数才是真正被调用的函数return _debounce
}
使用
const a =debounce(()=>{console.log('asd')})button.onclick(a)
button被点击的事件就被加上防抖函数了。
节流代码
限制代码访问频率,如某个代码1分钟只能执行一次。
自定义
时间戳
function throttle(func, wait) {var previous = 0;return function() {let now = Date.now();let context = this;let args = arguments;if (now - previous > wait) {func.apply(context, args);previous = now;}}
}
const throttledFn = throttle(count,1000);
定时器
function throttle(func, wait) {let timeout;return function() {let context = this;let args = arguments;if (!timeout) {timeout = setTimeout(() => {timeout = null;func.apply(context, args)}, wait)}}
}
复杂实现
// leading参数用来控制是否第一次立即执行,默认为true
function throttle(fn, interval, leading = true) {//该变量用于记录上一次函数的执行事件let lastTime = 0// 内部的控制是否立即执行的变量let isLeading = true// time 保存定时器的idlet time = nullconst _throttle = function(...args) {// 获取当前时间const nowTime = new Date().getTime()// 第一次不需要立即执行if (!leading && isLeading) {// 将lastTime设置为nowTime,这样就不会导致第一次时remainTime大于intervallastTime = nowTime// 将isLeading设置为false,这样就才不会对后续的lastTime产生影响。isLeading = false}// cd剩余时间const remainTime = nowTime - lastTime// 如果剩余时间大于间隔时间,也就是说可以再次执行函数if (remainTime - interval >= 0) {fn.apply(this, args)// 将上一次函数执行的时间设置为nowTime,这样下次才能重新进入cdlastTime = nowTime}if (remainTime < interval) {// 判断是否存在定时器,如果存在则取消掉if (time) clearTimeout(time)// 设置定时器time = setTimeout(() =>{// 由于该定时器,会在没有事件触发的interval时间间隔后才会执行,也就是说一轮事件// 执行已经结束,使用需要将isLeading复原,这样下一轮事件的第一次事件就不会立即执行了。isLeading = true}, interval)}}// 返回_throttle函数return _throttle
}
vueuse中工具类
const throttledFn = useThrottleFn(() => {// 操作,1s只能执行一次
}, 1000)
定时任务
手动实现
setInterval(() => {handleQuery();}, 1000 * 60 * 5);
setInterval不晓得为啥有时候有bug
// 定时器查询
function handleQueryByInterval() {setTimeout(() => {handleQuery();handleQueryByInterval();}, 1000 * 60 * 5);
}
工具类useInterval
useInterval(() => {handleQuery();}, 1000);