ts 函数防抖、函数节流

9,415 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

项目中遇到用户点击按钮会发送多次请求,会白白占用不必要的资源,

<template>
    <div class="home">
        <button @click="onCLick">快点我</button>
    </div>
</template>

<script lang="ts">
import {Component, Vue} from "vue-property-decorator";


@Component({
    components: {},
})
export default class Home extends Vue {
    onCLick() {
        console.log("我被点了,被点了。。。")
    }
}
</script>

image.png

思来想去发现可以用函数防抖来解决该问题。

函数防抖 (debounce)

  • 函数防抖: 在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时,先计算时间后执行。 说白了就是为了减少频繁发生的事件的资源请求,如果在等待时间内用户没有操作,则执行回调,如果有操作,继续等待相应时间间隔。

所以在闭包函数内,初始化一个时间参数timer,如果timer为空,则表示回调事件没执行或者已执行完毕,代表在等待时间内用户没有操作,相反,如果timer不为null,清空timer,重新计时。

<template>
    <div class="home">
        <button @click="onCLick">函数防抖</button>
    </div>
</template>

<script lang="ts">
import {Component, Vue} from "vue-property-decorator";
@Component({
    components: {},
})
export default class Home extends Vue {
    // eslint-disable-next-line @typescript-eslint/ban-types
    debounce(func: Function, time: number, immediate = false) {
        let timer: number | null = null;
        return (...args: any) => {
            if (timer) clearInterval(timer)
            if (immediate) {
                if (!timer) func.apply(this, args);
                timer = window.setTimeout(() => {
                    timer = null
                }, time)
            } else {
                timer = window.setTimeout(() => {
                    func.apply(this, args)
                }, time)
            }
        }
    }

    // onCLick = this.debounce(() => {
    //     console.log("我被点了,被点了。。。")
    // }, 500)
    onCLick = this.debounce(() => {
        console.log("我被点了,被点了。。。")
    }, 500,true)
}
</script>

函数节流 (throttle)

  • 函数节流: n秒内回调函数只会被执行一次,先执行后计算。 函数节流的目的是为了让函数在特定时间内执行一次,用setTimeout实现,执行完回调将timer置空。
<template>
    <div class="home">
        <button @click="onCLick">函数节流</button>
    </div>
</template>

<script lang="ts">
import {Component, Vue} from "vue-property-decorator";

@Component({
    components: {},
})
export default class Home extends Vue {
    // eslint-disable-next-line @typescript-eslint/ban-types
    throttle(func: Function, time: number, immediate = false) {
        if (immediate) {
            let prevTime = 0;
            return (...args: any) => {
                let nowTime = Date.now();
                if (nowTime - prevTime >= time) {
                    func.apply(this, args)
                    prevTime = nowTime
                }
            }
        } else {
            let timer: number | null = null;
            return (...args: any) => {
                if (!timer) {
                    func.apply(this, args)
                    timer = window.setTimeout(() => {
                        if (timer) clearInterval(timer)
                        timer = null
                    }, time);
                }
            }
        }

    }

    onCLick = this.throttle(() => {
        console.log("我被点了,被点了。。。")
    }, 500)
    // onCLick = this.throttle(() => {
    //     console.log("我被点了,被点了。。。")
    // }, 500, true)
}
</script>