img

什么是防抖和节流,他们的应用场景有哪些

2020-03-20 0条评论 2.8k次阅读 JavaScript


节流(throttle):固定时间内事件只执行一次

在固定时间内事件只执行一次。应用场景:高频的监听事件、滚动事件、input 框实时搜索并发送请求展示下拉列表,每隔一秒发送一次请求 (也可做防抖)

节流可以比作过红绿灯,每等一个红灯时间就可以过一批

代码如下,可以看出来节流重在加锁 timer=timeout

<!DOCTYPE html>
<html>
<head>
    <title>节流</title>
</head>
<body>
    <button onclick="clickBtn1()">使用时间戳</button>
    <button onclick="clickBtn2()">使用定时器</button>
<script type="text/javascript">


    let clickBtn1 = throttle1(function(){
        console.log("使用时间戳;无论你高频点多少次都会在n秒内执行一次,节流会稀释函数的执行频率")
    });

    let clickBtn2 = throttle2(function(){
        console.log(12312)
    });
    //高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

    //使用时间戳
    function throttle1(fn,wait = 300) {
        let time = 0;
        return function(){
            let _this = this;
            let args = arguments;
            let now = Date.now();
            if(now - time > wait) {
                fn.apply(_this,args);
                time = now;
            }
        }
    }

    // 使用定时器
    function throttle2(fn,wait = 300) {
        let timer;

        return function(){
            let _this = this;
            let args = arguments;

            if(!timer) {
                timer = setTimeout(function(){
                    timer = null;
                    fn.apply(_this,args);
                },wait);
            }
        }
    }
</script>
</body>
</html>

防抖(debounce):最后一个人说了算

多次事件只执行最后一次。应用场景:登录、发短信,调整浏览器窗口大小,文本编辑器实时保存,输入框输入事件,鼠标移动

防抖可以比作等电梯,只要有一个人进来,就需要再等一会儿。业务场景有避免登录按钮多次点击的重复提交。

代码如下,可以看出来防抖重在清零 clearTimeout(timer)

<!DOCTYPE html>
<html>
<head>
    <title>防抖</title>
</head>
<body>

<button onclick="clickBtn(1)">按钮</button>
<script type="text/javascript">
    let clickBtn = debounce(function(i){
        console.log("触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间")
    });
    //防抖,触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间
    function debounce(fn,wait = 300) {
        let timer;
        return function(){
            let _this = this;
            let args = arguments; // 是一个对应于传递给函数的参数的类数组对象
            if(timer) { clearTimeout(timer) }
            timer = setTimeout(function(){
                fn.apply(_this,args);
            },wait);
        }
    }
        // 拉扯你的浏览器窗口
        // window.onresize  = debounce(function(){
        //     console.log("resize")
        // });
</script>
</body>
</html>

Vue事件中使用方法

/**
 * utils/index.js
 * 节流
 * @param fn
 * @param wait
 * @returns {(function(): void)|*}
 */
export function throttle(fn,wait = 300) {
    let time = 0;
    return function(){
        let _this = this;
        let args = arguments;
        let now = Date.now();
        if(now - time > wait) {
            fn.apply(_this,args);
            time = now;
        }
    }
}
import {throttle} from "@/utils"

methods: {
    Send:throttle(function(id,name){
        // ...code
    })
}

不使用导入

function debounce(fn,wait = 500) {
  let timer;
  return function(){
    let _this = this;
    let args = arguments; // 是一个对应于传递给函数的参数的类数组对象
    if(timer) { clearTimeout(timer) }
    timer = setTimeout(function(){
      fn.apply(_this,args);
    },wait);
  }
}
export default {
  methods: {
      loadData() {
        this.getData(this)
    }
    getData: debounce(that => {
      that.limit += 10;
  }
}

如果是点击事件的话

<button @click="getArticleOrder(item)">点击</button>
methods: {
  // 解决获取不到this的问题
  //Duplicate keys detected: 'orderIndex'. This may cause an update error.
  setArticleOrder: debounce(function (...args) {
    this.getArticleOrderDebounce(...args)
  }),
  setArticleOrderDebounce(order) {
    if (order === this.orderIndex) return
    this.orderIndex = order
  }
}

💬 COMMENT


🦄 支持markdown语法

👋友