• 节流和防抖


    项目首页做了滚动加载,给鼠标绑定事件之后,用户的每一次滚动都会触发事件,这个会造成性能的浪费,节流和防抖可以帮助优化。
    其实不止 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)
    }
    }
    }

  • 相关阅读:
    GitHub代码阅读神器,你值有拥有!
    SpringBoot项目构建成jar运行后,如何正确读取resource下的文件
    基于SpringBoot-Dubbo的微服务快速开发框架
    基于SpringBoot的Web API快速开发基础框架
    野蛮生长的前端,从杂牌军到正规军
    让Redis突破内存大小的限制
    myeclipse 8.5-10.0 安装 svn 方法
    几秒后刷新页面
    不错的Spring学习笔记(转)
    Spring学习笔记(三)-类扫描的注解
  • 原文地址:https://www.cnblogs.com/gwf93/p/10147918.html
Copyright © 2020-2023  润新知