一文读懂防抖和截流
作者:互联网
本篇文章梗概:
什么是防抖和节流?
他们有什么区别?
分别如何实现?
什么是防抖和节流?
防抖和节流,都是开发过程中防止函数多次调用的方式。我现在写的主要是前端开发中的防抖和节流的介绍。
什么是防抖?
防抖,顾名思义,防止抖动,以免把一次事件误认为多次,敲键盘就是一个每天都会接触到的防抖操作。
想要了解一个概念,必先了解概念所应用的场景。在 JS 这个世界中,有哪些防抖的场景呢?
1. 登录、发短信等按钮避免用户点击太快,以致于发送了多次请求,需要防抖。
2. 调整浏览器窗口大小时,resize 次数过于频繁,造成计算过多,此时需要一次到位,就用到了防抖。
3. 文本编辑器实时保存,当无任何更改操作一秒后进行保存。
什么是节流?
节流,顾名思义,控制水的流量。控制事件发生的频率,如控制为1s发生一次,甚至1分钟发生一次。与服务端(server)及网关(gateway)控制的限流 (Rate Limit) 类似。
scroll 事件,每隔一秒计算一次位置信息等
浏览器播放事件,每个一秒计算一次进度信息等
input 框实时搜索并发送请求展示下拉列表,没隔一秒发送一次请求 (也可做防抖)
防抖和节流的区别
防抖:防止抖动,单位时间内事件触发会被重置,避免事件被误伤触发多次。代码实现重在清零 clearTimeout。
节流:控制流量,单位时间内事件只能触发一次,如果服务器端的限流即 Rate Limit。代码实现重在开锁关锁 timer=timeout; timer=null
防抖和节流的代码实现
防抖的实现
/** * 防抖(debounce)防止抖动:触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间。 * @param {*} func 调用用的函数,function * @param {*} wait 等待的时间,单位ms * @param {*} immediate 当immediate为true时,第一次调用该函数的时候,就调用func函数;false表示超时之后再调用 */ export function debounce(func, wait, immediate) { let timer; // 通过闭包缓存一个定时器 id return function () { // 将 debounce 处理结果当作函数返回 // 触发事件回调时执行这个返回函数 let context = this; // 把上下文的this对象保存下来,因为下面的apply要使用 let args = arguments; console.log(context,"90909090") // ...args:使用es6的rest运算符,把逗号隔开的值序列组合成一个数组:如test(1,2,3,4) ==> args:[1,2,3,4] // 符合apply(obj,[]) if (timer) clearTimeout(timer); //关键点 防抖重在清零 // 如果已经设定过定时器就清空上一次的定时器,clearTimeout取消延迟执行的代码块 if (immediate) { // 如果immediate为true,那么立马调用该函数 var callNow = !timer; timer = setTimeout(() => { timer = null; }, wait); if (callNow) func.apply(context, args); // 过了设定的时间,才执行传过来的函数 } else { // 开始设定一个新的定时器,定时器结束后执行传入的函数 fn timer = setTimeout(function () { func.apply(context, args); }, wait); } }; }
节流的实现
//这个是在上一个函数上的改进,加强版节流函数 throttle //如下,新增逻辑在于当前触发时间和上次触发的时间差小于时间间隔时,设立一个新的定时器,相当于把 debounce 代码放在了小于时间间隔部分。 export function throttle(fn, wait) { let timer = null; let prev = new Date(); return function () { let nowTime = new Date(); // 获取当前时间,转换成时间戳,单位毫秒 let context = this; clearTimeout(timer); // ------ 新增部分 start ------ // 判断上次触发的时间和本次触发的时间差是否小于时间间隔 // 如果小于,则为本次触发操作设立一个新的定时器 // 定时器时间结束后执行函数 fn if (nowTime - prev > wait) { fn.apply(context, arguments); prev = new Date(); // ------ 新增部分 end ------ } else { timer = setTimeout(() => { fn.apply(context, arguments); }, wait); } }; }
延伸:
es6 rest argument
es6 引入了rest参数(形式:...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。
var fun = (...item)=>{ console.log(item) } fun(11,22,33,44,55,66,77,88,99)
apply方法
apply:方法能劫持另外一个对象的方法,继承另外一个对象的属性.
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
用法:将数组作为函数参数
例子:Math.max后面可以接任意个参数,最后返回所有参数中的最大值。
一般这样做,需要取数组里面每个值,毕竟很多传参是接受对象的
function getMax(arr){ var arrLen=arr.length; for(var i=0,ret=arr[0];i<arrLen;i++){ ret=Math.max(ret,arr[i]); } return ret; }
用apply就简单很多
function getMax2(arr){ return Math.max.apply(null,arr); }
这样看来`...args`,使用es6的rest运算符,把逗号隔开的值序列组合成一个数组:如test(1,2,3,4) ==> args:[1,2,3,4],
`apply`把数组转成对象。这里args是继承的传入函数的参数。
防抖代码,关键就是,对象转换两遍,clearTimeout取消延迟执行的代码块,清零。
其实不管防抖和截流还有很多其他方法,都可以用loadash类库去实现,不用自己苦哈哈的写。
标签:防抖,节流,args,timer,读懂,apply,截流,函数 来源: https://www.cnblogs.com/youqiancheng/p/14659123.html