防抖和节流的概念和实现

首先,我们需要先搭建一个页面用来测试

<!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>
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    
    <div id="Box"></div>

    <div id="BoxTwo">
        <ul>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
            <li>1</li>
        </ul>
    </div>

    <script src="./js.js"></script>
</body>
</html>

样式:

body{
    margin: 0;
}

#Box{
    width: 600px;
    height: 600px;
    background: #f1f1f1;
    border: 1px solid #000;
    margin: 100px auto 0;
}

#BoxTwo{
    width: 600px;
    height: 600px;
    background: #f1f1f1;
    border: 1px solid #000;
    margin: 100px auto 20px;
    overflow-y: scroll;
}

防抖:

为什么使用防抖?

原因:

如果我们监听一个页面的滚动或者监听一个输入框用户的输入,那么每一次滚动或者每一次输入都会触发对应的监听方法

如果方法中进行了比较复杂的操作,在这一次触发的计算还没计算完成之前,又触发了下一次,就会造成浏览器的卡顿

这时我们就要对这些监听进行一个优化 避免高频率的触发

应用场景:

高频率触发一个函数

注意 : 高频率回调函数也会造成卡顿的情况 所以我们可以设置一个停顿的时间

原理:

当监听事件触发后一段事件没有再次触发,则执行事件,如果在执行之前再次触发,则重新计时

代码:

function debounce(func, wait) { // 防抖函数1 初级
    let timeOut; // 计时器
    // console.log(this); 这里的this指向window
    // 这里使用了闭包的写法,所以这个timeOut是属于下面这个函数的全局变量
    return function () {
        // console.log(this); 这里的this指向Box元素
        clearTimeout(timeOut); // 销毁计时器
        timeOut = setTimeout(() => {
            func(1); // 传递参数
        }, wait) // 将计时器赋值给timeOut
    }
}

function debounceTwo(func, wait) { // 防抖函数2  通过apply优化了this的指向  通过arguments优化了参数传递的问题
    let timeOut;

    return function () {
        let that = this
        let args = arguments
        clearTimeout(timeOut)

        timeOut = setTimeout(function () {
            func.apply(that, args)
        }, wait)
    }
}

function debounceThree(func, wait, immediate) { // 防抖函数3 加入了首次触发的功能 通过第三个参数控制
    let timeOut; // 计时器
    return function () {
        if (timeOut) clearTimeout(timeOut); // 有计时器才能销毁计时器

        var that = this;
        var args = arguments;

        if (immediate) {
            func.apply(that, args)
            immediate = false
        } else {
            timeOut = setTimeout(function () {
                func.apply(that, args)
            }, wait)
        }
    }
}

function boxMouseFun() {
    console.log(this);
    console.log(arguments);
}

(function () {
    let Box = document.querySelector("#Box");
Box.addEventListener('mousemove',boxMouseFun) // 鼠标一直移动的话 这个事件就会被持续性不间断的触发 会给浏览器带来一些负担

Box.addEventListener('mousemove', debounce(boxMouseFun, 2000));
// 这样已经实现了简单的防抖
// 这里有个问题 我们的boxMouseFun方法是由Box元素调用起来的 正常来说 这个方法的this应该指向Box元素 而现在指向的是window

Box.addEventListener('mousemove',debounceTwo(boxMouseFun,2000));
// 我们需要一个首次触发一次 然后再次执行时触发防抖函数的防抖功能

Box.addEventListener('mousemove', debounceThree(boxMouseFun, 2000, true)); // 优化了首次执行后再次触发是防抖函数

})()

节流:

为什么使用节流?

原因:

当我们持续触发某一个事件时 例如我们下拉刷新来请求一个接口 如果闲着没事频繁的下滑 频繁的请求接口 十分的消耗性能 因为请求一般来说都是异步请求 在这一次的数据返回之前 下一次请求又来了 会十分的卡顿

应用场景:

图片懒加载

数据请求

原理:

当持续触发事件时,保证一定时间段内只调用一次事件处理函数

代码:

function throttle(func, time) { // 时间戳原理节流
    let startDate = Date.now(); // 开始时间的时间戳
    return function () {
        let that = this
        let args = arguments
        let triggerDate = Date.now(); // 结束时间的时间戳
        if (triggerDate - startDate >= time) {
            func.apply(that, args);
            startDate = Date.now()
        }
    }
}

function throttleTwo(func, time) { // 定时器原理节流
    let timer = null; // 定时器

    return function () {
        if (!timer) { // 定时器为空时可触发
            let that = this
            let args = arguments
            timer = setTimeout(function () { // 给定时器赋值
                func.apply(that, args)
                timer = null // 重置定时器
            }, time)
        }
    }
}

function throttleThree(func,time){ // 时间戳优化版
    let startTime=0,that,args;

    return function(){
        let triggerTime = Date.now(); // 触发时间
        if(triggerTime - startTime > time){
            func.apply(that,args);
            startTime = triggerTime
        }
    }
}

function BoxScrollFunc() {
    // console.log(this); // 指向元素
    console.log(1111);
}

(function () {
    let Box = document.querySelector("#BoxTwo");
    Box.addEventListener('scroll', throttle(BoxScrollFunc, 1000)) // 触发时间的时间戳和触发后更新开始时间的时间戳来实现节流 首次立即执行 然后一秒内不可再次触发
    Box.addEventListener('scroll', throttleTwo(BoxScrollFunc,1000)) // 定时器初始化为null 触发后给定时器赋值 有值的定时器不在触发事件 触发事件后再给定时器赋值为null 如此反复实现节流 首次一秒后执行 然后一秒内不可再次触发
    Box.addEventListener('scroll',throttleThree(BoxScrollFunc,1000)) // 时间戳节流的优化版本 初始时间设为0 通过触发事件减去初始时间大于间隔时间触发事件 触发事件后将初始时间赋值为触发时间
})()

节流和防抖的总结:

防抖: 在频繁的触发事件后一段时间执行事件

节流: 在频繁的触发事件中控制,一段时间最多只能触发一次事件

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值