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

    节流和防抖这是两个类似又有些不同的优化方案

    日常开发过程中,滚动事件做复杂计算频繁调用回调函数很可能会造成页面的卡顿,这时候我们更希望把多次计算合并成一次,只操作一个精确点,JS把这种方式称为debounce(防抖)和throttle(节流)

    节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率。即:在指定时间之内,让函数只触发一次。
    防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间。即:对于一定时间段的连续的函数调用,只让其执行一次。

    节流(debounce)

    throttle在英语里的意思是节流阀,顾名思义,设置一个阀值(制定一个时间),在这个阀值或者时间之内,函数只会执行一次。

    实现函数节流我们主要有两种方法:时间戳和定时器

    举个例子,我们执行页面滚动的时候,比如在react里面,可能每次滚动都会触发一次render,这样严重影响性能,甚至会造成浏览器卡死。如果我们设置一个300ms的时间阀,那么在这段时间内,滚动时候只会触发一次render.

    同样的,当我们拖拽某个元素的时候,会每次判断mousemove时跟位置相关的信息,每次都会执行相关的计算和判断,这种情况就和滚动时候一样,如果设置一个时间阀,那么就可以避免由于大量执行事件计算而造成的性能下降。

    • 实现方式:每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法
    • 缺点:如果事件在规定的时间间隔内被不断的触发,则调用方法会被不断的延迟
    function throttle(fn,times = 300){
        let bool = true
        return function(){
            if(!bool){
                return false
            }
            bool = false
            setTimeout(()=>{
                bool = true
                fn.apply(this,arguments)
            },times)
        }
        
    }

    或者

    onresize问题,页面满屏布局,模块很多dom结构也相对复杂。所以在窗口频繁快速变化大小的时候页面反应异常卡顿。

    //问题解决的原理就是事件节流
    
    window.onresize = () => {
          console.log('resize')
    }

    解决办法如下:

     let timer = null
              window.onresize = () => {
                    console.log(timer)
                    if (!timer) {
                        timer = setTimeout(() => {
                            callBack()
                            timer = null
                        }, 1000)
                    }
                }
    
                function callBack() {
                    console.log('resize')
                }

    封装起来:

    //封装前我们先思考一下,首先既然是封装那么事件不一定都是onersize、间隔时间得有用户设置、callBack得是用户写。
    
    **其实我们只关心callBack,和执行间隔时间,恰好事件都有回调
    
                function callBack() {
                    console.log('resize')
                }
    
                function throttle(callBack, time) {
                    let timer = null
                    //timer状态要常驻内存,这里做了一个闭包
                    return function() {
                        if (!timer) {
                            timer = setTimeout(() => {
                                callBack()
                                timer = null
                            }, time)
                        }
                    }
                }
    
                window.addEventListener('resize', throttle(callBack, 1000), false)

    防抖(throttle)

    防抖实现起来的思路是,用闭包保存执行的函数,多次执行的时候把上一个执行的函数清除掉,然后再次创建一个新的函数。这样在间隔时间内还有事件触发的话,不会执行之前的函数,这么一来,函数真正的执行就是最后一次事件触发。

    实现方式:每次触发事件时,如果当前有等待执行的延时函数,则直接return

    function debounce(fn,times){
        let timeout = null
        return function(){
            clearTimeout(timeout)
            timeout = setTimeout(()=>{
                fn.apply(this,arguments)
            },times)
        }
    }

    总结:

    函数防抖:将多次操作合并为一次操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。

    函数节流:使得一定时间内只触发一次函数。原理是通过判断是否有延迟调用函数未执行。

    区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。

    两者都是在密集调用的过程中灵活使用setTimeout函数来对频繁触发的事件进行控制和优化。

  • 相关阅读:
    POJ 1320 Street Numbers 解佩尔方程
    数学分支(转)
    深入理解Java类加载器(1):Java类加载原理解析
    Java类加载器的工作原理
    深入理解Java:类加载机制及反射
    类加载机制:全盘负责和双亲委托
    java底层学习
    代码面试最常用的10大算法
    程序员面试金典算法题
    了解ASCII、gb系列、Unicode、UTF-8的区别
  • 原文地址:https://www.cnblogs.com/huxiuxiu/p/13492434.html
Copyright © 2011-2022 走看看