题图 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 = 3000
function 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上面。
针对上面的过程,我们给节流下一个定义:事件一直触发,我们获取事件触发时间,比较两次触发时间的间隔,当这个时间间隔达到某个阀值的时候,触发事件处理逻辑。
关联文章:白话防抖。
以上便是节流的简单实现,如果你有什么建议或者想法欢迎留言。
欢迎转发、关注、点击好看