分类: web前端 | 标签: 防抖 节流

js的防抖和节流

发表于: 2023-02-12 10:09:09 | 字数统计: 1.3k | 阅读时长预计: 6分钟

B站视频教程: JS_防抖_节流

防抖

搜索框带来的问题

需求:根据输入框内容来请求数据

<!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="searchTxt" type="search" placeholder="请输入关键字检索">
    <script>
        document.querySelector("#searchTxt").oninput = function(){
            console.log('发送请求,当前输入框值:',this.value)
        }
    </script>
</body>
</html>

上面的代码会带来一个问题:用户每输入一个关键字都会触发

image-20230212103615638

现在是要求是用户停下来不输入的时候再触发一次,这个时候就需要用到防抖函数了

实现的思路

  1. 事件函数执行,先创建个定时器
  2. 逻辑代码放到定时器
  3. 当函数再次触发,清除定时器
  4. 创建一个新定时器即可

案例

<!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="searchTxt" type="search" placeholder="请输入关键字检索">
    <script>
        let t = null
        document.querySelector("#searchTxt").oninput = function(){
            clearTimeout(t) //有定时器则清除
            t = setTimeout(() => {
                console.log('发送请求,当前输入框值:',this.value)
            }, 1000);
        }
    </script>
</body>
</html>

image-20230212104119184

封装防抖函数

<!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="searchTxt" type="search" placeholder="请输入关键字检索">
    <script>
        document.querySelector("#searchTxt").oninput = debounce(function(){
            console.log('发送请求,当前输入框值:',this.value)
        })
        //封装一个公共的防抖函数
        function debounce(fn){//将函数逻辑放入fn中
            let t = null //此处利用闭包保存定时器
            return function(){
                clearTimeout(t) //有定时器则清除
                t = setTimeout(() => {
                    //箭头函数指向外面函数的this,而外面函数由input触发
                    fn.call(this) //利用call改变fn的this,否则fn的this为undefined
                }, 1000);
            }
        }
    </script>
</body>
</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>
    <style>
        .box{
            height: 1000px;
        }
    </style>
</head>
<body>
    <div class="box">

    </div>
    <script>
        document.onscroll = function(){
            console.log('发送ajax,请求下一页数据')
        }
    </script>
</body>
</html>

上面的代码会带来一个问题:用户轻轻下拉滚动条,onscroll中的逻辑会触发很多次

image-20230212111058652

现在是要求是降低触发事件的频率,这个时候就需要用到节流函数了。

实现的思路

  1. 事件函数执行,先判断是否有定时器,有则直接return
  2. 把逻辑代码放到定时器
  3. 定时器执行后,置空定时器变量

案例

<!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>
    <style>
        .box{
            height: 1000px;
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <script>
        let t = null
        document.onscroll = function(){
            if(null != t) return //关键点1:有定时器则return
            t = setTimeout(() => {//关键点2:逻辑代码放到定时器中
                console.log('发送ajax,请求下一页数据')
                t = null  //关键点3:定时器执行完毕,置空定时器变量
            }, 500);
        }
    </script>
</body>
</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>
    <style>
        .box{
            height: 1000px;
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <script>
        
        document.onscroll = throttle(function () {
            console.log('发送ajax,请求下一页数据',this)
        })

        //封装一个节流函数
        function throttle(fn) {
            return function(){
                //这里用的是fn.t变量的形式来保存定时器变量
                if(null != fn.t) return 
                fn.t = setTimeout(() => {
                    fn.call(this)
                    fn.t = null
                }, 500);
            }
        }
    </script>
</body>
</html>
------ 本文结束,感谢您的阅读 ------
本文作者: 贺刘芳
版权声明: 本文采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。