• 使用rxjs以及javascript解决前端的防抖和节流


    JavaScript实现方式:

    防抖

    触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间;
    思路:每次触发事件时都取消之前的延时调用方法:

    举个例子:做一个自动查询的功能
    假装下面的代码是从服务器获取的数据(下面会用到):// 假装这是个接口function getData(val){    returnnew Promise(function(resolve, reject){

            setTimeout(function(){
                if(!val){resolve([]);return;}
                var json = [
                    {name:"萧山国际机场",jianpin:"xsgjjc",threeCode:"xjc"},
                    {name:"北京南苑机场",jianpin:"bjnyjc",threeCode:"byc"},
                    {name:"上海虹桥机场",jianpin:"shhqjc",threeCode:"hcg"},
                    {name:"成都机场",jianpin:"cdjc",threeCode:"cjc"}
                ];
                var newJson = json.filter(function(item){
                    return item.name.indexOf(val)==0||item.jianpin.indexOf(val)==0||item.threeCode.indexOf(val)==0
                });
                resolve(newJson);
            },1000)
        })
    }
    在文本框输入关键字去服务器实时请求对应的数据,如下代码;<body>
        <input type="text" placeholder="简拼/汉字/三字码" id="test"/>
        <script>
            var $test = document.getElementById('test');
            $test.onkeyup =autoSearch;
            function autoSearch(){
                var val = $test.value;
                getData(val).then(function(res){console.log(res)})
            }   
        </script>
    </body>
    结果如下图,在运行的时候会发现存在一个问题:这个函数的默认执行频率太高了,高到什么程度呢?我们输入"萧山",函数执行了9次!,然而我们需要的只是最后一次.

    然而实际上我们并不需要如此高频的反馈,毕竟浏览器和服务器的性能是有限的,所以接着讨论如何优化这种场景。

    function debounce(fn,delay){
        let timer = null
        //闭包
        return function() {
            if(timer){
                clearTimeout(timer) 
            }
            timer = setTimeout(fn,delay)
        }
    }
    
    // 改写上面的代码
    ...
     $test.onkeyup = debounce(autoSearch,1000);
    ...

    再次运行结果就是我们想要的结果了:

    节流

    高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率。
    思路:每次触发事件时都判断当前是否有等待执行的延时函数。

    还是上面的例子:如果某个用户闲的蛋疼,一直按着键盘不撒手,那么只要她在1秒内重新按了键盘,就永远不会有结果输出,但是我们还想要在某个时间间隔之后给出反馈呢

    使用方法跟debounce一样。代码逻辑也类似。在触发时超过间隔时间interval ms则执行。否则不执行。if判断中的setTimeout是保证最后一次事件触发后能够调用,所以每次执行没到间隔时间时先清除timer,再重新启动timer。而在达到间隔时间时执行函数。代码逻辑也很简单,不用多说,相信聪明的你一看就能明白。

    function throttle(fn,interval){
        var last;
        var timer;
        var interval=interval||200;
        return function(){
            var th=this;
            var args=arguments;
            var now=+new Date();
            if(last&&now-last<interval){
                clearTimeout(timer);
                timer=setTimeout(function(){
                    last=now;
                    fn.apply(th,args);
                },interval);
            }else{
                last=now;
                fn.apply(th,args);
            }
        }
    }
    
    // 改写上面的代码
    ...
     $test.onkeyup = throttle(autoSearch,1000);
    ...

    运行结果就是我们想要的结果了(不管文本框输入什么内容,没1秒输出一次结果):

    rxjs实现方式

    使用rxjs,使用起来更方便(要记得要安装或者引入rxjs哦)
    使用debounceTime(防抖)和throttleTime(节流)操作符,对流进行限制,然后再订阅符合规则的流,输出想要的数据即可,
    rxjs的可以参考官方文档.https://cn.rx.js.org/
    也可以查看Rx观测的交互图:
    debounceTime: https://rxmarbles.com/#debounceTime
    throttleTime:https://rxmarbles.com/#throttleTime
    例子:

    <head>
        <script src="https://cdn.bootcss.com/rxjs/6.0.0-alpha.3/Rx.min.js"></script>
    </head>
    
    <body>
    防抖:<input type="text" placeholder="简拼/汉字/三字码" id="debounce"/><br/><br/>
    节流:<input type="text" placeholder="简拼/汉字/三字码" id="throttle"/>
    <script>
        var $debounce = document.getElementById('debounce');
        var $throttle = document.getElementById('throttle');
        const debounce$ = Rx.Observable.fromEvent($debounce, 'input');
        const throttle = Rx.Observable.fromEvent($throttle, 'input');
        // 节流
        debounce$
            .debounceTime(1000)
            .subscribe(function (e) {
                var value = e.target.value;
                console.log('防抖:'+value)
            });
        // 防抖
        throttle
            .throttleTime(1000)
            .subscribe(function (e) {
                var value = e.target.value;
                console.log('节流:'+value)
            });
    </script>
    </body>

    结果:



  • 相关阅读:
    【报错】ES报错找不到Gson类
    【报错】Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
    【JUC】AtomicInteger源码
    【Netty】Netty服务启动源码
    【Netty】Netty实现简单RPC
    【Netty】心跳机制
    【Netty】Netty模型
    【Netty】Reactor模型
    C# 好狂的多线程呀
    select使用
  • 原文地址:https://www.cnblogs.com/darkbluelove/p/11418106.html
Copyright © 2020-2023  润新知