zoukankan      html  css  js  c++  java
  • 节流和防抖

    项目首页做了滚动加载,给鼠标绑定事件之后,用户的每一次滚动都会触发事件,这个会造成性能的浪费,节流和防抖可以帮助优化。
    其实不止 scroll 事件,resize 事件、鼠标事件(比如 mousemove、mouseover 等)、键盘事件(keyup、keydown 等)都存在被频繁触发的风险。

    “节流”与“防抖”的本质

    这两个东西都以闭包的形式存在。

    它们通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率。

    Throttle: 第一个人说了算

    throttle 的中心思想在于:在某段时间内,不管你触发了多少次回调,我都只认第一次,并在计时结束时给予响应。

    Debounce: 最后一个人说了算

    防抖的中心思想在于:我会等你到底。在某段时间内,不管你触发了多少次回调,我都只认最后一次。

    优化

    debounce 的问题在于它“太有耐心了”。试想,如果用户的操作十分频繁——他每次都不等 debounce 设置的 delay 时间结束就进行下一次操作,于是每次 debounce 都为该用户重新生成定时器,回调函数被延迟了不计其数次。频繁的延迟会导致用户迟迟得不到响应,用户同样会产生“这个页面卡死了”的观感。

    为了避免弄巧成拙,我们需要借力 throttle 的思想,打造一个“有底线”的 debounce——等你可以,但我有我的原则:delay 时间内,我可以为你重新生成定时器;但只要delay的时间到了,我必须要给用户一个响应。

    下面是对应的三种实现:


    let last = 0, timer = null; // 把上次触发事件和定时器存在全局

    /**
    * 防抖
    * @param fn
    * @param delay
    * @returns {Function}
    */
    debounce=(fn, delay)=>{
    // let timer = null;
    // 将debounce处理结果当作函数返回
    return function () {
    // 保留调用时的this上下文
    let context = this
    // 保留调用时传入的参数
    let args = arguments

    // 每次事件被触发时,都去清除之前的旧定时器
    if(timer) {
    clearTimeout(timer)
    }
    // 设立新定时器
    timer = setTimeout(function () {
    fn.apply(context, args)
    }, delay)
    }
    }
    /**
    * 节流
    * @param fn
    * @param interval
    * @returns {Function}
    */
    throttle=(fn, interval)=>{
    // 将throttle处理结果当作函数返回
    return function () {
    // 保留调用时的this上下文
    let context = this
    // 保留调用时传入的参数
    let args = arguments
    // 记录本次触发回调的时间
    let now = +new Date()

    // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
    if (now - last >= interval) {
    // 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
    last = now;
    fn.apply(context, args);
    }
    }
    }
    /**
    * 节流防抖结合
    * @param fn
    * @param delay
    * 用 Throttle 来优化 Debounce
    */
    throttle=(fn, delay)=>{
    // 将throttle处理结果当作函数返回
    return function(){
    // 保留调用时的this上下文
    let context = this;
    // 保留调用时传入的参数
    let args = arguments;
    // 记录本次触发回调的时间
    let now = +new Date()

    // 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
    if(now - last < delay){
    console.log("不触发")
    clearTimeout(timer)
    timer = setTimeout(function(){
    last = now;
    fn.apply(context, args);
    }, delay)
    }else{
    console.log("触发")
    // 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
    last = now
    fn.apply(context, args)
    }
    }
    }

  • 相关阅读:
    Android 解决小米手机Android Studio安装app 报错的问题It is possible that this issue is resolved by uninstalling an existi
    Android Unresolved Dependencies
    Android studio 自定义打包apk名
    Android Fragment与Activity交互的几种方式
    魅族和三星Galaxy 5.0webView 问题Android Crash Report
    Android几种常见的多渠道(批量)打包方式介绍
    Android批量打包 如何一秒内打完几百个apk渠道包
    上周热点回顾(9.30-10.6)团队
    上周热点回顾(9.23-9.29)团队
    上周热点回顾(9.16-9.22)团队
  • 原文地址:https://www.cnblogs.com/gwf93/p/10147918.html
Copyright © 2011-2022 走看看