【JS手写系列】手写实现防抖和节流

352 阅读2分钟

靡不有初,鲜克有终

不积跬步无以至千里

手写实现防抖和节流

0、前言

  • 防抖、节流这两个词语,做前端的肯定不陌生(但你很熟悉吗🐶)
  • 容易混淆,而且一旦让手写实现,就容易触及到大家的知识盲区,死活想不起来,DDDD哈哈
  • 本文除了用于记录自己手写JS相关知识,也可以给大家做一个快速demo参考
  • 话不多说,进入正题👇

1、防抖

应用场景:

  • 适合大量事件一次响应

典例:

  • input框的change触发事件
  • 按钮的快速点击(当然,你也可以玩loading来解决)

思路:

  • 在事件被持续触发n秒后再执行回调,如果在这n秒内又被触发,则清除timer重新计时。

1.1、简易版本

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head><body>
    <div>
        <span>没有防抖:</span>
        <input type="text" id="unDebounce">
    </div>
    <br>
    <div>
        <span>有防抖:</span>
        <input type="text" id="debounce">
    </div>
</body><script>
    const unDebounceDom = document.getElementById('unDebounce')
    unDebounceDom.addEventListener('keyup', function () {
        ajax()
    })
​
    const debounceDom = document.getElementById('debounce')
    debounceDom.addEventListener('keyup', function () {
        debounce(ajax, 500)
    })
​
    // 假设这是一个请求
    function ajax () {
        console.log('发起了一个ajax请求!')
    }
​
    // 简单版本
    let timer = null;
    function debounce (fn, delay) {
        timer && clearTimeout(timer);
        timer = setTimeout(function () {
            fn();
        }, delay);
    }
​
</script>

</html>

1.2、常规版本

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head><body>
    <div>
        <span>没有防抖:</span>
        <input type="text" id="unDebounce">
    </div>
    <br>
    <div>
        <span>有防抖:</span>
        <input type="text" id="debounce">
    </div>
</body><script>
    const unDebounceDom = document.getElementById('unDebounce')
    unDebounceDom.addEventListener('keyup', function (e) {
        ajax(e.target.value)
    })
​
    const debounceDom = document.getElementById('debounce')
    debounceDom.addEventListener('keyup', function (e) {
        debounceAjax(e.target.value)
    })
​
  
    let debounceAjax = debounce(ajax, 500)
​
    function debounce (fun, delay) {
        let timer
        return function () {
            let that = this
            let args = arguments // 当前return函数接收的参数
            timer && clearTimeout(timer)
            timer = setTimeout(function () {
                console.log(that); // window
                fun.call(that, ...args)
                // fun.apply(that, args)
            }, delay)
        }
    }
​
    // 假设这是一个请求
    function ajax (content) {
        console.log('发起了一个ajax请求:' + content)
    }
​
</script></html>

2、节流

应用场景:

  • 适合大量事件按固定时间平均触发

典例:

  • 监听滚动
  • resize 事件

思路:

  • 在事件被持续触发平均每n秒执行一次回调,如果再次触发的时刻小于上次执行时间加延时的和,则清除timer重新计时。

具体实现:

<!DOCTYPE html>
<html lang="en"><head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head><body>
    <div>
        <span>没有节流:</span>
        <input type="text" id="unThrottle">
    </div>
    <br>
    <div>
        <span>有节流:</span>
        <input type="text" id="throttle">
    </div>
</body><script>
    const unDebounceDom = document.getElementById('unThrottle')
    unDebounceDom.addEventListener('keyup', function (e) {
        ajax(e.target.value)
    })
​
    const debounceDom = document.getElementById('throttle')
    debounceDom.addEventListener('keyup', function (e) {
        throttleAjax(e.target.value)
    })
​
​
    let throttleAjax = throttle(ajax, 1000)
​
    // 节流
    function throttle (fun, delay) {
        let timer
​
        // 上次执行时间戳
        let lastTime
​
        return function () {
            let that = this
            let args = arguments
​
            // 执行此刻时间戳
            let nowTime = +new Date()
​
            // 如果此刻时间是小于上次时间加延时的和,则清空timer重新进入延时
            if (lastTime && nowTime < lastTime + delay) {
                clearTimeout(timer)
                timer = setTimeout(function () {
                    lastTime = nowTime
                    fun.apply(that, args)
                }, delay)
            } else {
                lastTime = nowTime
                fun.apply(that, args)
            }
        }
    }
​
    // 假设这是一个请求
    function ajax () {
        console.log('发起了一个ajax请求!')
    }
​
</script></html>

3、总结

图片.png

  • 用心理解上面防抖、节流的相关描述文案和代码,思路应该会变得很清晰的
  • 代码是直接放的全部的html,方便拷贝直接进行测试

📑 最后,也欢迎大家阅读我的【JS手写系列】的其他文章

本文相关的优质参考链接👇:

码字不易,欢迎点赞🚀🚀🚀