JavaScript实现防抖与节流

1. 防抖与节流

1.1 定义

在一定时间之内, 只允许触发事件一次, 防止多次触发.

1.2 区别
  • 防抖的意义在执行的是用户最后一次触发的事件, 而节流执行的是用户第一次触发的事件.
1.3 场景重现
  • 防抖: 输入搜索框随时监听用户键盘输入, 及时返回关于搜索的关键字供用户选择, 如何解决用户敲一下键盘我们就调用一次服务器, 频繁调用服务器, 增大服务器的开销的问题?
  • 节流: 前端调用服务端接口, 在接口没有返回的同时, 我们如何防止用户再次点击事件按钮多次执行数据?
1.4 解决思路
  • 防抖: 我们可以 延迟执行 触发函数, 一旦还没有执行函数用户再次触发事件, 那么我们抛弃上一步的事件执行最新一次的事件. 关键字 延迟执行. 核心代码如下:
 // 监听键盘事件模拟搜索场景.
        let shakeTimeOut = null;
        searchBox.addEventListener("keyup", function () {
            let value = searchBox.value.trim();
            if (!value) {
                return false;
            }
            // 只要重新输入清空以前的定时任务
            if (shakeTimeOut) {
                clearTimeout(shakeTimeOut);
            }
            // 重新定义最新的定时任务
            shakeTimeOut = setTimeout(function () {
                // 真正执行函数部分
                console.debug(value);
            }, 1000);
        });
  • 节流 我们可以 通过控制一段时间内关键字状态 来执行函数. 核心代码如下:
			// 利用 saveStreamFlag 关键字控制代码执行
        let saveStreamFlag = true;
        searchBtn.addEventListener("click", function () {
            if (!saveStreamFlag) {
                console.debug("搜索值太频繁");
                return false;
            }
            saveStreamFlag = false;
            saveStream();
            // 执行 saveStream() 方法的时间不会影响改变 saveStreamFlag标识改变的时间
            setTimeout(function () {
                saveStreamFlag = true;
              // 我们可以预估方法执行的时间来改变标识的时间
            }, 1000);
        });
1.5 逻辑代码

代码中涉及到了利用H5创建本地数据库, 一旦触发搜索, 我们将用户搜索的记录存储在数据库中, 利用input[list] 和datalist 标签实现输入搜索框的实现(代码中涉及背景图片和字体资源请忽略).

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <title>Js实现防抖和节流</title>
</head>
<style type="text/css">
    * {
        margin: 0;
        padding: 0;
    }

    /*定义外部网络字体*/
    @font-face {
        font-family: WebFont;
        src: url("font/ErZiYuanMoFaShaoNvJian-2.ttf");
    }

    body {
        font-family: WebFont;
        font-size: 20px;
        background: black;
    }
    #box {
        margin: auto;
        width: 1280px;
        height: 800px;
        background-image: url("image/backend.jpg");
        background-size: cover;
        border: none;
    }

    #content {
        position: fixed;
        top: 20%;
        left: 50%;
        transform: translateX(-50%);
        display: table;
        text-align: center;
        color: #e91e63;
    }

    #content section {
        display: inline-block;
        width: 500px;
        height: 300px;
    }

    #preventShakeBox input{
        height: 30px;
        line-height: 30px;
        outline: none;
        border-radius: 5px;
        border: none;
        padding-left: 5px;
    }
    #preventShakeBox input::placeholder {
        color: #999999;
    }

    #saveStreamBox input{
        height: 30px;
        line-height: 30px;
        outline: none;
        border-radius: 5px;
        border: none;
        padding: 0 20px;
        cursor: pointer;
    }

    #saveStreamBox input:hover {
        background-color: #e91e63;
        color: #ffffff;
    }

</style>
<body>
    <div id="box">
        <section id="content">
            <h1>Js实现防抖与节流</h1>
            <section id="preventShakeBox">
                <h2>防抖</h2>
                <!--利用 input 和 datalist 标签绑定实现可输入和下拉的功能-->
                <input type="text" placeholder="请输入要搜索的值" aria-label="防抖" list="data" id="searchBox"/>
                <datalist id="data">
                </datalist>
            </section>
            <section id="saveStreamBox">
                <h2>节流</h2>
                <input type="button" value="搜索" id="searchBtn">
            </section>
        </section>
    </div>
</body>
<script type="text/javascript">
    /*将搜索的值存入本地数据库*/
    let db = openDatabase("db_search", "1.0", "test prevent shake and save stream", 1024 * 1024 * 2);
    let searchBtn = document.getElementById("searchBtn");
    let searchBox = document.getElementById("searchBox");
    let data = document.getElementById("data");

    // 创建数据库
    db.transaction(function (transaction) {
        transaction.executeSql(" drop table if exists search_history");
        transaction.executeSql(" create table search_history ( key varchar(255) unique not null)" ,
            [], function () {
            console.debug("数据库创建成功");
        }, function (transaction, error) {
            console.debug("数据库创建失败, 失败原因是: " + error.message);
        });
    });

    window.onload = function () {

        // 将搜索的值插入数据库并刷新datalist的值
        let saveStreamFlag = true;
        searchBtn.addEventListener("click", function () {
            if (!saveStreamFlag) {
                console.debug("搜索值太频繁");
                return false;
            }
            saveStreamFlag = false;
            saveStream();
            // 执行 saveStream() 方法的时间不会影响改变 saveStreamFlag标识改变的时间
            // 我们可以预估方法执行的时间来改变标识的时间
            setTimeout(function () {
                saveStreamFlag = true;
            }, 1000);
        });



        // 监听键盘事件模拟搜索场景.
        let shakeTimeOut = null;
        searchBox.addEventListener("keyup", function () {
            let value = searchBox.value.trim();
            if (!value) {
                return false;
            }
            // 只要重新输入清空以前的定时任务
            if (shakeTimeOut) {
                clearTimeout(shakeTimeOut);
            }
            // 重新定义最新的定时任务
            shakeTimeOut = setTimeout(function () {
                console.debug(value);
            }, 1000);
        });
    };

    // 刷新datalist的值
    function flushDataList(transaction) {
        transaction.executeSql("select * from search_history", [], function (transaction,resultSet) {
            let rows = resultSet.rows;
            let options = "";
            for (let i = 0; i < rows.length; i++) {
                let name = rows[i].key;
                console.debug(name);
                options += `<option value="${name}">${name}</option>`;
            }
            data.innerHTML = options;
        }, function (transaction, error) {
            console.debug("查询历史记录失败, 失败原因为: " + error.message);
        });
    }

    function saveStream() {
        const value = searchBox.value.trim();
        if (!value) {
            console.debug("搜索参数不能为空");
            return false;
        }
        console.debug("参加搜索的值为: " + value);
        db.transaction(function (transaction) {
            transaction.executeSql("select * from search_history where key = ? ", [new Object(value)], function (transaction, resultSet) {
                let rows = resultSet.rows;
                if (rows.length <= 0) {
                    transaction.executeSql("insert into search_history(key) values( ? )", [new Object(value)], function () {
                        console.debug("插入成功");
                    }, function (transaction, error) {
                        console.debug("插入失败, 失败原因: " + error.message);
                    });
                    flushDataList(transaction);
                }
            }, function (transaction, error) {
                console.debug("查询历史记录失败, 失败原因为: " + error.message);
            });
        });
    }

</script>
</html>

猜你喜欢

转载自blog.csdn.net/qq844579582/article/details/89072710