让你彻底了解什么是节流

题图 By HymChu From lnstagram

 

上一篇文章咱们介绍了防抖,这一篇文章大咱们讨论一下节流,同样咱们看一个需求:页面中有一个文本框,文本框根据用户的输入,发送异步请求关联数据,显示在输入框下面。

 

初步实现代码如下:

 

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <meta http-equiv="X-UA-Compatible" content="ie=edge">    <title>Document</title></head><body><input type="text" name="" id="inp"><script>    document.querySelector("#inp").oninput = function(){        console.log("22222")    } </script></body></html>

 

不考虑性能的话,功能完全能实现,但是我们看一下控制台,input只要一有输入,就会调用事件函数,我们发现这是不必要的,有的朋友可能想到了上一篇文章的防抖,用防抖也可以实现这个功能,但是用防抖的话有一个小问题,那就是等用户完全输入停止后才去发送异步请求。

 

但是我们需要用户输入时候到某个时间节点,不论用户有没有输入完成都发送一次异步请求,用户持续的输入,持续的触发input事件,只要到达某事时间间隔,就发送一次ajax。这样操作会提升用户体验。

 

按照上面的描述,咱们来思考一下如何实现上面的代码,首先应该有一个全局变量来获取当前的时间starttime,然后触发input事件的时候,获取触发事件的当前时间currenttime,然后对比两个时间的时间差,如果插值大于等于规定的时间间隔timespace,发送ajax,并且更新starttime,如果小于时间间隔timesapce,不做处理,代码流程图如下:

 

 

按照流程图,代码实现如下:

 

<script>var starttime = Date.now();var currenttime = null;var timespace = 3000function ajax(){    console.log("异步请求,渲染dom")}document.querySelector("#inp").oninput = function(){        currenttime = Date.now();    if(currenttime-starttime>timespace){        ajax()        starttime = Date.now();    }else{        console.log("不做处理")    }} </script>

 

仔细阅读代码,发现代码又bug,当用户完全输入后,反而不会触发ajax。所以我们要进行处理,添加一个判断,判断用户输入完成后,触发ajax请求,代码修改如下:

 

<script>var starttime = Date.now();var currenttime = null;var timespace = 3000// 添加延时器全局变量var timeout = null;function ajax(){    console.log("异步请求,渲染dom")}document.querySelector("#inp").oninput = function(){    currenttime = Date.now();    if(currenttime-starttime>timespace){        clearTimeout(timeout);        starttime = Date.now();        timeout = null;        ajax()    }else{        // 判断有无定时器        if(!timeout){            // 没有定时器的话,打开定时器        timeout = setTimeout(function(){                ajax();                // 调用完成后将timeout清空                timeout = null;            },4000)        }    }}</script>

 

这次基本实现了节流的应用,我们看到节流一般和防抖结合使用,因为节流的最后要判断用户是否输入完成。

 

上面的代码依然有好多问题,暴露了多个全局变量,不能复用,更改代码如下:

 

<script>function ajax(){    console.log("异步请求,渲染dom")}function throttle(callback){    var starttime = Date.now();    var currenttime = null;    var timespace = 3000    var timeout = null;        return function(){        // 用context和event保存调用事件的this和事件对象    var context = this;    var event = arguments[0]    currenttime = Date.now();    if(currenttime-starttime>timespace){        clearTimeout(timeout);        starttime = Date.now();        timeout = null;        // 使callback绑定事件调用对象,和事件对象        callback.call(context,event)    }else{        // 判断有无定时器        if(!timeout){            // 没有定时器的话,打开定时器        timeout = setTimeout(function(){            // 使callback绑定事件调用对象,和事件对象            callback.call(context,event)                // 调用完成后将timeout清空                timeout = null;            },4000)        }    }}}document.querySelector("#inp").oninput = throttle(ajax)</script>

 

我们实现了throttle函数,这个函数可以将事件的主要逻辑函数变为一个节流函数,并且我们根据throttle返回的函数最终调用者为inputDom,所以用变量context和event保存调用事件逻辑的this和事件对象,然后将其绑定到callback上面。

 

针对上面的过程,我们给节流下一个定义:事件一直触发,我们获取事件触发时间,比较两次触发时间的间隔,当这个时间间隔达到某个阀值的时候,触发事件处理逻辑。

 

关联文章:白话防抖。

 

以上便是节流的简单实现,如果你有什么建议或者想法欢迎留言。

欢迎转发、关注、点击好看

posted @ 2019-03-12 20:27  挥刀  阅读(1226)  评论(0编辑  收藏  举报