详解节流的概念并手动实现节流函数

一、节流的概念和使用库实现节流

1.1. 认识节流
  • 节流:当事件第一次被触发时,就会执行相应的回调函数。但是如果这个事件被频繁的触发的话,相应的函数并不会被频繁的执行,而是会以固定的频率执行。不管在这个频率之内触发多少次事件,函数的执行频率都是固定的
1.2. underscore实现节流
  • underscore中实现了throttle(节流)方法,调用这个方法,将想要绑定在事件上的回调函数作为参数传入throttle方法即可
_.throttle(fn, time)
<input type="text">

    <!-- 通过CDN引入文件 -->
    <script src="https://cdn.jsdelivr.net/npm/underscore@1.13.6/underscore-umd-min.js"></script>

<script>

     const inputEl = document.querySelector("input")
     let count = 0
     inputEl.oninput = _.throttle(function() {
        console.log("发送网络请求", count++, this.value)
     },5000)

</script>

二、手写节流实现

2.1. 基本实现
<body>

    <input type="text">

    <script>

        // 1.基本实现
        function zdThrottle(fn, intervalTime) {

            let startTime = 0
            function _throttle() {
                const nowTime = new Date().getTime()
                const waitTime = intervalTime - (nowTime - startTime)
                if (waitTime <= 0) {
                    fn()
                    startTime = nowTime
                }
            }

            return _throttle

        }

    </script>

    <script>

        const inputEl = document.querySelector("input")
        let count = 0

        inputEl.oninput = zdThrottle(function() {
            console.log(`发送网络请求${count++}`, this.value)
        }, 2000)


    </script>

</body>
2.2. this和参数的绑定、取消立即执行
<body>

    <input type="text">

    <script>

        // 2.this和参数的绑定、取消立即执行
        function zdThrottle(fn, intervalTime, leading = true) {

            let startTime = 0
            function _throttle(...args) {
                const nowTime = new Date().getTime()

                // 想要取消立即执行,就让第一次事件触发调用函数时的waitTime大于0即可
                if (!leading && startTime === 0) {
                    startTime = nowTime
                }

                const waitTime = intervalTime - (nowTime - startTime)

                if (waitTime <= 0) {
                    fn.apply(this, args)
                    startTime = nowTime
                }
            }

            return _throttle

        }

    </script>

    <script>

        const inputEl = document.querySelector("input")
        let count = 0

        inputEl.oninput = zdThrottle(function(event) {
            console.log(`发送网络请求${count++}`, this.value, event)
        }, 2000, false)


    </script>

</body>
2.3. 开启尾部执行:最后就算在规定的时间,事件没有触发,也照常执行一次回调函数
<body>

    <input type="text">

    <script>

        // 3.开启尾部执行
        function zdThrottle(fn, intervalTime, { leading = true, trailing = false } = {}) {

            let startTime = 0
            let timer = null

            function _throttle(...args) {
                const nowTime = new Date().getTime()

                if (!leading && startTime === 0) {
                    startTime = nowTime
                }

                const waitTime = intervalTime - (nowTime - startTime)

                if (waitTime <= 0) {
                    if (timer) clearTimeout(timer)
                    fn.apply(this, args)
                    startTime = nowTime
                    timer = null
                }

                if (trailing && !timer) {
                    timer = setTimeout(() => {
                        fn.apply(this, args)
                        // 一定要将现在的时间重新通过new Date()获得再赋给开始时间
                        // 不能拿上面的nowTime的原因是因为...用文字有点难表达,但是跟事件循坏和事件队列中的任务执行时机是有							关的,自己多想一下即可
                        startTime = new Date().getTime()
                        timer = null
                    }, waitTime)
                }

            }

            return _throttle

        }

    </script>

    <script>

        const inputEl = document.querySelector("input")
        let count = 0

        inputEl.oninput = zdThrottle(function(event) {
            console.log(`发送网络请求${count++}`, this.value, event)
        }, 2000, { leading: false, trailing: true })


    </script>

</body>
2.4. 取消最后一次执行的功能
<body>

    <input type="text">
    <button class="cancel">取消</button>

    <script>

        // 4.添加取消执行的功能
        function zdThrottle(fn, intervalTime, { leading = true, trailing = false } = {}) {

            let startTime = 0
            let timer = null

            function _throttle(...args) {
                const nowTime = new Date().getTime()

                if (!leading && startTime === 0) {
                    startTime = nowTime
                }

                const waitTime = intervalTime - (nowTime - startTime)

                if (waitTime <= 0) {
                    if (timer) clearTimeout(timer)
                    fn.apply(this, args)
                    startTime = nowTime
                    timer = null
                }

                if (trailing && !timer) {
                    timer = setTimeout(() => {
                        fn.apply(this, args)
                        startTime = new Date().getTime()
                        timer = null
                    }, intervalTime)
                }

            }

            // 一个函数也是对象,所以是可以给添加一个方法的
            _throttle.cancel = function() {
                clearTimeout(timer)
            }

            return _throttle

        }

    </script>

    <script>

        const inputEl = document.querySelector("input")
        const cancelEl = document.querySelector(".cancel")
        let count = 0

        // 这个返回的函数(对象)里面有cancel方法,直接调用即可取消最后一次的函数执行
        const returnValue = zdThrottle(function(event) {
            console.log(`发送网络请求${count++}`, this.value, event)
        }, 2000, { trailing: true })

        inputEl.oninput = returnValue

        cancelEl.onclick = function() {
            returnValue.cancel()
        }


    </script>

</body>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值