js中的防抖节流:性能优化和用户体验碰撞

212 阅读5分钟

防抖(Debounce)和节流(Throttle)是前端开发中常用的性能优化技术,尤其在处理高频事件时,比如窗口大小调整、滚动、键盘输入等。它们都旨在减少事件触发的频率,以提高性能和用户体验。

防抖(Debounce)

原理

防抖的原理是将多次执行合并为一次。具体来说,当事件被频繁触发时,防抖函数会在每次事件触发后延迟执行,只有在延迟时间内没有再次触发事件时,才会真正执行事件处理函数。

实现

function debounce(func, wait) {
  let timeout;
  return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(() => func.apply(this, args), wait);
  };
}

应用场景

  1. 输入框联想搜索:在用户输入停止后进行搜索,而不是每次输入字符都进行搜索。
  2. 窗口大小调整:在用户停止调整窗口大小后再执行调整后的操作。

实例

防抖:创建一个防抖项目,其中目录包括前端和后端,后端JSON Server模拟网页从数据库中拿数据的过程,前端写一个html页面输入框模拟用户输入自己账号名字提示从数据库中拿值出来

image.png

npm run dev把json-server跑起来 端口号3000

image.png

image.png

自己创建用户表

image.png

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        没有防抖的input 
        <input type="text"
        id = "unDebounce"
        placeholder="请输入用户名">
    </div>

    <div>
        防抖的input 
        <input type="text"
        id = "debounce"
        placeholder="请输入用户名">
    </div>
    <script>
        //不加防抖的
        const inputa = document.getElementById('unDebounce');
        const inputb = document.getElementById('debounce');
        function handleNameSearch(e) {
            // console.log(e.target.value)
            const value = e.target.value;
            fetch('http://localhost:3000/users')
                .then(res => res.json())
                .then(data =>{
                    // console.log(data)
                    const users = data;
                    const filterUsers = users.filter(user => {
                       
                        //数组上的新方法 map转换 filter过滤
                        //callback回调函数
                        return user.name.includes(value)//es6中新方法,可读性好
                        // return user.name.indexOf(value) !== -1//可读性差
                       
                    })
                    console.log(filterUsers)
                })
        
        }
        //闭包
        function debounce(func,delay){
            //返回值必须得是函数 keyup  事件处理函数
            //let id;
            return  function(args){
                clearTimeout(func.id)//清除定时器
                //函数是一个对象, id 挂在func上 func是闭包中的自由变量
                func.id = setTimeout(function(){
                    func(args)
                },delay)
            }
        }
        const debounceNameSearch = debounce(handleNameSearch, 500)//闭包功能函数
        //减少服务器端的压力,0.5秒
        inputa.addEventListener('keyup',handleNameSearch)
        inputb.addEventListener('keyup',debounceNameSearch)
    </script>
</body>
</html>

事件event

- keyup 快速找到你想要的数据
    猜你喜欢
    ajaxSuggest
    googleSuggest ,最早google发明

- ajax 向服务器请求数据
    动态修改页面的能力

- 服务器的能力
    - 并发
    - 总连接数是有上限的
    - CPU / 内存
    

效果展示

没有加防抖,在每次输入字符时都进行搜索

image.png

加了防抖,只有键盘输入停止设置的时间才会返回最后一次搜索

image.png

优点

  • 减少不必要的函数执行,降低性能开销。
  • 提升用户体验,使应用反应更加灵敏和直观。

节流(Throttle)

原理

节流的原理是限制函数的执行频率。具体来说,节流函数会在一定时间间隔内只执行一次事件处理函数,即使事件被多次触发。

实现

function throttle(func, wait) {
  let lastTime = 0;
  return function(...args) {
    const now = Date.now();
    if (now - lastTime >= wait) {
      lastTime = now;
      func.apply(this, args);
    }
  };
}

应用场景

  1. 滚动事件:限制滚动事件处理函数的执行频率,减少计算和渲染的次数。
  2. 按钮点击:防止按钮在短时间内被多次点击,导致多次提交或执行。

实例

节流

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流</title>
</head>
<body>
    <div class="raw">
        <div>
            没有节流的input <input type="text" id="inputa">
        </div>
        <div>
            有节流的input <input type="text" id="inputc">
        </div>
    </div>
    <script>
        const inputa = document.getElementById('inputa');
        const inputc = document.getElementById('inputc');

        // 节流函数,限制函数的执行频率
        const throttle = (func, delay) => {
            let lastTime;  // 记录上次函数执行的时间
            let deferTimer;  // 延迟执行的定时器

            // 返回一个新的函数,这个函数在触发事件时会执行节流逻辑
            return (...args) => {
                const now = +new Date();  // 获取当前时间

                if (lastTime && now < lastTime + delay) {
                    // 如果两次触发间隔小于delay,重置定时器
                    clearTimeout(deferTimer);
                    deferTimer = setTimeout(() => {
                        lastTime = now;
                        func(...args);  // 延迟执行函数
                    }, delay);
                } else {
                    lastTime = now;  // 记录当前时间
                    func(...args);  // 立即执行函数
                }
            };
        };

        // 模拟一个耗时的Ajax请求
        const ajax = (content) => {
            console.log(`ajax request ${content}`);
        };

        // 没有节流的输入框,输入时每次触发事件都会调用ajax
        inputa.addEventListener('keyup', (e) => {
            ajax(e.target.value);
        });

        // 创建一个节流函数,间隔为1000毫秒
        const throttleFunc = throttle(ajax, 1000);

        // 有节流的输入框,输入时会调用节流函数
        inputc.addEventListener('keyup', (e) => {
            throttleFunc(e.target.value);
        });
    </script>
</body>
</html>

效果

没有加节流:每一次输入都被敏锐的拿到,非常耗费性能

image.png

加了节流:在输入每间隔一段时间执行一次,提升性能

image.png

优点

  • 控制事件处理函数的执行频率,保证在高频触发的情况下,函数能够在预定时间间隔内执行一次。
  • 提升性能,减少不必要的资源消耗。

比较与选择

  • 防抖:适合那些在高频率事件停止后才需要执行的场景,例如输入框的实时搜索。在这些场景中,防抖可以避免大量不必要的计算和网络请求。
  • 节流:适合那些需要持续执行且需要限制执行频率的场景,例如滚动事件处理。在这些场景中,节流可以确保函数在规定的时间间隔内执行一次,从而降低对浏览器性能的影响。

性能优化与用户体验

  1. 性能优化

    • 防抖和节流可以显著减少高频事件的处理次数,从而降低CPU和内存的使用。
    • 通过减少不必要的DOM操作和重绘重排,提高应用的整体性能。
  2. 用户体验

    • 防抖可以使用户输入等操作更加流畅,不会因为频繁的网络请求或计算而卡顿。
    • 节流可以使滚动、拖拽等操作更加平滑,防止因为过多的事件处理导致卡顿。

总结来说,防抖和节流是提升前端性能和用户体验的重要手段。在实际开发中,应根据具体场景选择合适的方法,避免不必要的性能消耗和用户体验的下降。