节流和防抖概念以及应用

2,308 阅读2分钟

防抖节流的相同与不同

防抖

定义:

触发事件后,函数在n秒内只执行一次,如果事件再次触发,则会重新计算函数执行时间

实际应用:

(1) input输入框频繁输入,进行模糊查找。在最后一次键盘抬起后的一秒,进行数据请求

节流

定义:连续触发的事件中,函数只在n秒内执行一次

实际应用:

(1) 点击按钮请求数据请求,如果频繁点击,对于网络不好,或者返回数据慢的情况。会造成页面数据混乱,那我们规定在n秒内只执行一次,就能很好的稀释这个频繁请求

(2) 浏览器的scroll()滚动事件,在图片赖加载的时候,我们需要监听浏览器的滚动位置,来加载图片。这个时候可以用节流,来稀释监听的频率,哪怕是100毫秒,也是很大的优化了。无论加载多块,都有时间差

(3) 浏览器的onresize()缩放,在pc适配移动端时,如果需要频繁监听浏览器的缩放,来判断当前页面展示是pc还是移动端。

概念使用总结

  1. 节流和防抖,都是解决频繁性事件的回调,造成页面性能消耗,卡顿
  2. (如果不设置立即执行)防抖是只在最后最后一次事件执行时触发
  3. (如果不设置立即执行)节流是在稀释了执行频率,在连续触发的事件中,函数在n秒只执行一次

防抖函数实现

普通版

实现输入框防抖

<!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>
    <input id="getId" />
</body>
<script>
    let id = document.getElementById('getId')
    function debounce(callBack, delay) {
        let timeout  // 这里使用闭包。在当前事件执行完毕之后,在下次事件执行时,依然保存上一次变量的状态
        return function (value) {
            console.log('参数', value)
            if (timeout) clearTimeout(timeout) // 每次事件触发,都要清空定时器,重新计算下次执行时间
            timeout = setTimeout(() => {
                callBack(value) // 外部输出结果,所以用了个回调函数
            }, delay)
        }
    }
    function getData(e) {
        console.log('一秒后输出', e)
    }
    let debounceFunc = debounce(getData, 1000)
    id.addEventListener('keyup', function (e) {
        debounceFunc(e.target.value)
    })
</script>

</html>

节流实现

时间戳和定时器版

<!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>
    <button id="btn">节流</button>
</body>
<script>
    let btn = document.getElementById('btn')
    // 时间戳版(立即执行)
    // function throttle(func, wait) {
    //     let prev = 0
    //     return function () {
    //         let now = new Date
    //         if (now - prev > wait) {
    //             // 立即执行
    //             func()
    //             prev = now
    //         }
    //     }
    // }
    // 定时器版(等到wait之后执行)
    function throttle(func, wait) {
        let timeout
        return function () {
            if (!timeout) // 如果定时器存在,就不执行
            {
                timeout = setTimeout(() => {
                    func()
                    timeout = null // 执行完毕,记得清空,方便下一次定时器判断
                }, wait);
            }
        }
    }
    // 如果我想第一次延迟wait执行,最后一个如果没有wait了,那我立即执行
  // function throttle(fn, wait) {
    //     let timeout = null
    //     let prev = 0
    //     return function () {
    //         let now = Date.now()
    //         let remaiing = wait - (now - prev)
    //         if (remaiing <= 0) {
    //             fn.apply(this, arguments)
    //         } else {
    //             timeout = setTimeout(() => {
    //                 fn.apply(this, arguments)
    //             }, remaiing)
    //         }
    //     }
    // }
    function func() {
        console.log('doSomething')
    }
    btn.onclick = throttle(func, 1000)
</script>

</html>

后续文章输出

  1. 案例版图片赖加载实现(节流应用)
  2. onresize,输出文章。带移动端适配(节流应用)
  3. 改变this指向实现call,apply,bind(js知识点)