zoukankan      html  css  js  c++  java
  • 防抖(debounce)和节流(throttle) 通俗说明 + 示例

    最近在面试,被问到防抖和节流的问题,虽然平时也有用电梯函数这种延时执行的代码,但是被问到概念的时候还是有点懵逼,所以赶紧来学习一下,分享一下学习成果,顺便把自己写的demo贴到下面,感兴趣的同学可以直接复制下面代码作为一个react组件引入到代码中,打开不同的注释掉的函数,看看效果,体验一下就明白了。

    防抖(debounce)和节流(throttle)

    首先明确一点防抖(debounce) 和 节流(throttle) 都是对函数执行的控制,因为某些事件会频繁的触发,例如 scroll mouseMove resize 等...

    • 防抖:是固定延时后执行,例如延时1s后执行一次,每次触发事件都会重置这个延时,防抖处理过的函数会推迟执行,假如你一直触发事件,防抖处理过的函数就一直不执行。
    • 节流:是固定时间执行一次,例如固定1秒执行一次,每次调用函数不会推迟执行,假如你一直触发事件,节流处理过的函数还是会1s执行一次。

    this 的指向问题 (延伸)

    • 箭头函数不绑定this,没有argument参数,它使用的this是作用域继承来的this
    • es5函数的this,指向函数的调用者
    • call, apply, bind 可以改变this的指向
    • argument参数是从执行的函数的作用域中获取的

    例子

    • 下面这个例子可以copy到react执行环境中查看效果,同时this的指向问题,也可以在代码中提现
    • 可以新建一个js文件把当前代码复制到xx.js 文件中,在其他地方引用该组件体验
    import React, { Component } from 'react'
    
    /**
     *
     * 防抖:防抖是指限制访问次数,在n秒内执行一次,但是如果在n秒内再次触发的话,会等待n秒再次执行
     * 节流:节流是指限制访问频率,是每n秒触发一次 
     * @param {*} fn 回调函数
     * @param {*} time 触发间隔
     */
    
    function debounce(fn, time) {
        let timer;
        return function () {
            const [x,y] = [...arguments];
            if (timer) {
                clearTimeout(timer)
            }
            timer =  setTimeout(fn.bind(this, x,y), time);  
        }
    }
    
    
    /**
     * 立即执行的防抖函数
     *
     * @param {*} fn 回调函数
     * @param {*} time 触发间隔
     * @returns
     */
    function rightNowDebounce(fn,time) {
        let timer;
        return function () {
            const [x,y] = [...arguments];
            if (timer) {
                clearTimeout(timer)
            } else {
                fn.apply(this, [x,y]);
            }
            timer =  setTimeout(fn.bind(this,x,y), time);  
        }
    }
    
    /**
     *
     * 时间差形式的防抖 (实现形式一)
     * @param {*} fn 回调函数
     * @param {*} durition 触发间隔
     * @returns
     */
    function durationThrottle(fn, durition) {
        let startTime;
        return function () {
            const [x,y] = [...arguments]
            if (startTime) {
                let cur = new Date().getTime();
                if (cur - startTime > durition) {
                    startTime = cur;
                    fn.apply(this, [x,y])
                }
            } else {
                startTime = new Date().getTime();
            }
        }
    }
    
    /**
     * 定时器形式的节流 (实现方式二)
     *
     * @param {*} fn 回调函数
     * @param {*} timer 触发间隔
     */
    function timerThrottle(fn, duration) {
        let timer
        return function () {
            const args = [...arguments]
            console.log('args', args)
            if (!timer) {
                timer = setTimeout(function() {
                    fn.apply(this, args);
                    timer = null;
                }.bind(this), duration);
            }
        }
    }
    
    /**
     *
     * 会立即执行的节流函数
     * @param {*} fn
     * @param {*} durition
     * @returns
     */
    
    function rightNowThrottle(fn, durition) {
        let startTime;
        return function () {
            const [x,y] = [...arguments]
            if (startTime) {
                let cur = new Date().getTime();
                if (cur - startTime > durition) {
                    startTime = cur;
                    fn.apply(this,[x,y])
                }
            } else {
                fn.apply(this,[x,y])
                startTime = new Date().getTime();
            }
        }
    }
    
    const fn1 = function () {
        const [x,y] = [...arguments]
        this.setState(function name({number}) {
            return {number: number+1, positionX:x, positionY:y} 
        })
    } 
    
    const definedDebounce = debounce(fn1, 1000)
    const definedRightNowDebounce = rightNowDebounce(fn1, 1000)
    const definedThrottle = durationThrottle(fn1, 1000)
    const definedRightNowThrottle = rightNowThrottle(fn1, 1000)
    const definedTimerThrottle = timerThrottle(fn1, 1000)
    
    export default class Debous extends Component {
        state = {
            number: 0,
            positionX: 0,
            positionY: 0,
        }
    
        hoverContaienr = (e) => {
            const { clientX, clientY } = e
             definedDebounce.apply(this, [clientX, clientY])
            // definedRightNowDebounce.apply(this, [clientX, clientY])
            // definedThrottle.apply(this, [clientX, clientY])
            // definedRightNowThrottle.apply(this, [clientX, clientY])
            // definedTimerThrottle.apply(this, [clientX, clientY])
    
            
        }
    
        render() {
            return (
                <div 
                    style={{  '100%', height:300, background:'pink', fontSize:'36px',textAlign:'center' }}
                    onMouseMove={this.hoverContaienr}
                >
                    <div style={{position:'absolute', top: '50%', left:'50%', transform:'translate(-50%, -50%)'}}>
                        {this.state.number}
                        <span style={{fontSize:16, color: '#333'}}>({`${this.state.positionX},${this.state.positionY}`})</span>
                    </div>
                </div>
            )
        }
    }
    
    

    参考文档 防抖节流

  • 相关阅读:
    Spark2.x学习笔记:Spark SQL程序设计
    Spark2.x学习笔记:Spark SQL的SQL
    Spark2.x学习笔记:Spark SQL快速入门
    Hystrix入门执行过程
    redis配置master-slave模式
    MockServer 入门
    Locust分布式负载测试工具入门
    poi读取excel元素
    hadoop+spark集群搭建入门
    Vi文档
  • 原文地址:https://www.cnblogs.com/wuhaozhou/p/14256172.html
Copyright © 2011-2022 走看看