参考:
https://blog.csdn.net/weixin_48594833/article/details/123460177
https://www.jianshu.com/p/c8b86b09daf0 <— 必看
基础参考:
https://zhuanlan.zhihu.com/p/676609830
概念说明
防抖 | 节流 | |
---|---|---|
定义 | 一定时间内,动作连续触发情况下,动作只执行一次,都是触发n秒之后执行动作,(立即执行就是先执行一遍) | 一定时间内,只给执行一次动作(加锁不给执行) |
作用 | 限制执行次数,防止卡顿、延迟、假死等 | 同 |
原理 | 刷新定时器,在定时器里面定时器结束才能执行fn | 一段时间内,加锁不给执行fn |
实现 | 都可以使用 setTimeout + clearTimeout 实现 | 同 |
场景 | 用户输入事件等 | 多是监听dom滚动等高触发事件。多是和后端有关。 |
用户一直触发时 | 定时器一直重新赋值,执行<=1(立即执行版会先执行一次) | n秒内会执行一次 |
代码实现
<template>
<div class="test">
<div class="content" @mousemove="fn4">
{{ num }}
</div>
</div>
</template>
<script>
export default {
name: 'test',
data() {
return {
num: 1,
fn1: this.debounce(this.count, 2000), // 只有这样才有用
fn2: this.debounceI(this.count, 2000), // 只有这样才有用
fn3: this.throttle(this.count, 2000), // 只有这样才有用
fn4: this.throttleT(this.count, 2000), // 只有这样才有用
}
},
// created() {
// },
methods: {
count() {
console.log('count')
this.num++
},
count1() {
console.log('count1')
this.debounce(this.count, 2000)() // 错误,每次move都会绑定一个定时器,只是延迟2秒触发一系列count
},
// 防抖:"频繁触发”一个事件时,limit 毫秒内只执行一次
// 非立即执行的防抖函数
debounce(fn, limit) {
let time
return function () {
let context = this
let args = arguments
if (time) clearTimeout(time) // 触发时,如果有锁, 就清除掉,以最新生成的锁(定时器)为准
time = setTimeout(() => {
fn.apply(context, args)
}, limit) // 每次都更新 time(锁), 定 limit 之后执行函数,将其推到堆中执行
}
},
// 立即执行的防抖函数
debounceI(fn, limit) {
let time
return function () {
let context = this
let args = arguments
if (time) clearTimeout(time) // 如果有旧锁,把锁去掉
let callNow = !time // 锁是否加上
time = setTimeout(() => {
time = null
}, limit) // 赋值新锁,limit 之后解除锁
if (callNow) fn.apply(context, args) // 没锁的时候执行
}
},
// 合并: 防抖函数
debounceFinal(fn, limit, immediate) {
let time
return function () {
let context = this
let args = arguments
if (time) clearTimeout(time)
if (immediate) {
// 立即执行, limit ms 内不能再执行
var callNow = !time
time = setTimeout(() => {
time = null
}, limit)
if (callNow) fn.apply(context, args)
} else {
// 延迟limit之后执行,值得注意的是:以频繁触发的最后一次为开始时间计算
time = setTimeout(() => {
fn.apply(context, args)
}, limit)
}
}
},
// 节流:连续触发事件时 n 秒只执行一次函数
// 时间戳版
throttle(fn, limit) {
let previous = 0
return function () {
let now = Date.now()
let context = this
let args = arguments
if (now - previous > limit) {
fn.apply(context, args) // 函数会立即执行,并且每 limit ms 执行一次
previous = now
}
}
},
// 定时器版
throttleT(func, limit) {
let timeout
return function () {
let context = this
let args = arguments
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args) // 函数不会立即执行,并且每 kimit ms 执行一次,在停止触发事件后,函数还会再执行一次。
}, limit)
}
}
},
// 合并: 节流函数
throttleFinal(func, limit, type) {
let previous = 0
let timeout
return function () {
let context = this
let args = arguments
if (type === 1) {
let now = Date.now()
if (now - previous > limit) {
func.apply(context, args)
previous = now
}
} else if (type === 2) {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null
func.apply(context, args)
}, limit)
}
}
}
},
/*
*/
},
}
</script>
<style>
.content {
height: 150px;
line-height: 150px;
text-align: center;
color: #fff;
background-color: #ccc;
font-size: 80px;
}
</style>