手写JS防抖和节流(面试高频)

防抖:

什么是防抖?

首先我们想象一下这个场景,如果在一个区域内设置鼠标移动事件,那一旦我们将鼠标移入这个区域内,这个事件就会被持续触发,导致每次改变都会重新渲染一次页面让性能损耗很大,这种情况下我们就需要用到防抖,那究竟什么是防抖呢?

  触发高频事件后一段时间内函数只会执行一次,如果这段时间内高频事件再次被触发,则重新计算时间;

 <div id="contain">

    </div>
    <button id="btn">点击取消防抖</button>
    <script>
        //创建一个防抖函数
        function deBounce(fun, wait, immediate) {
            var timer, result
            let debounced = function () {
                // 改变this的指向问题
                let _this = this
                let args = arguments
                // console.log(args)
                clearTimeout(timer)
                if (immediate) {
                    // 立即执行的函数
                    let callNow = !timer
                    timer = setTimeout(() => {
                        timer = null
                    }, wait)
                    if (callNow) result = fun.apply(_this, args)
                } else {
                    timer = setTimeout(() => {
                        result = fun.apply(_this, args)
                    }, wait)
                }
                return result
            }
            debounced.cancel = function () {
                clearTimeout(timer)
                timer = null
            }
            return debounced
        }
        let count = 0
        let container = document.querySelector('#contain')
        let btn = document.querySelector('#btn')

        function changeCount() {
            console.log(this)
            container.innerHTML = count++
        }
        let chCount = deBounce(changeCount, 3000)
        btn.onclick = function () {
            console.log(chCount);
        }
        // 使用防抖处理
        container.onmousemove = chCount
        // 不使用防抖处理
        // container.onmousemove = changeCount
    </script>

</body>

上述代码中在3s内如果触发了onmousemove时间就会清除定时器重新开始计时。

防抖使用应用场景:

  1.             scoll窗口滚动事件
  2.              搜索框输入查询
  3.              表单验证
  4.               按钮提交事件
  5.               浏览器窗口缩放——resize事件

节流:

什么是节流?

在一段时间内一直触发某个函数,每隔一段时间该函数只执行一次。

通常我们实现节流有两种方式:基于定时器和基于时间戳来实现

基于定时器:
 

// 创建节流函数
        function throttle(fun, wait) {
            //声明保存this,参数,计时器的变量
            let _this, args, timer

            return function () {
                // 改变this指向
                _this = this
                args = arguments
                if (!timer) {
                    timer = setTimeout(() => {
                        timer = null
                        fun.apply(_this, args)
                    }, wait)
                }
            }

        }

该方法的不足在于——不顾头顾尾(第一次不执行,最后一次执行)。

基于时间戳实现:

function throttle(fun, wait) {
            let _this, args
            // 之前的时间戳
            let previous = 0
            return function () {
                // 获取当前时间戳
                _this = this
                args = arguments
                let now = new Date().valueOf()
                if (now - previous > wait) {

                    fun.apply(_this, args)
                    //立即执行
                    previous = now
                }
            }

        }

该方法的不足在于——顾头不顾尾(第一次调用立即执行,最后一次调用失效)。

既然上述两个方法一个不顾头,一个不顾尾,那我们就可以将两种方法混合在一起就产生了一个完美的解决方案——混合实现

 //    混合实现————顾头顾尾
        function throttle(fun, wait) {
            let _this, args, timer
            // 之前的时间戳
            let previous = 0
            let later = function () {
                previous = new Date().valueOf()
                timer = null
                fun.apply(_this, args)
            }
            return function () {
                // 获取当前时间戳
                _this = this
                args = arguments
                let now = new Date().valueOf()
                if (now - previous > wait) {
                    if (timer) {
                        clearTimeout(timer)
                        timer = null
                    }

                    fun.apply(_this, args)
                    //立即执行
                    previous = now
                } else if (!timer) {
                    timer = setTimeout(later, wait)
                }
            }

        }

节流的应用场景:

        1.dom元素的拖拽实现

        2.计算鼠标移动的距离

        3.监听scroll滚动事件

        4.后台请求数据时可以使用节流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值