题图 By HymChu From lnstagram
上一篇文章咱们介绍了防抖,这一篇文章大咱们讨论一下节流,同样咱们看一个需求:页面中有一个文本框,文本框根据用户的输入,发送异步请求关联数据,显示在输入框下面。
初步实现代码如下:
<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 = 3000var 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上面。
针对上面的过程,我们给节流下一个定义:事件一直触发,我们获取事件触发时间,比较两次触发时间的间隔,当这个时间间隔达到某个阀值的时候,触发事件处理逻辑。
关联文章:白话防抖。
以上便是节流的简单实现,如果你有什么建议或者想法欢迎留言。
欢迎转发、关注、点击好看