说明

image.png
image.png
简单说明:
都是为了防止事件频繁执行。

防抖:停止触发一段时间后,再执行函数(比如回城技能,要读条一段时间后才能回城)
节流:不管怎么触发,每一段时间内,只能执行函数1次(比如射击,不管你鼠标点多快,每秒只能发射那么多子弹)

===============

防抖 debounce函数

问题

image.png
比如淘宝搜索,在这里搜索,输入文字,下面会出现弹出框对你输入的文字进行联想,帮助用户选择。

弹出的联系,可能是发送网络请求到服务器,请求联想的信息。

如果我每输入1个文字,就发送一次,我输入了4个就发送4次,很浪费性能,而且对服务器造成很大压力。

这个时候如果可以优化,比如我输入后等待500毫秒都没有输入东西了,才发生请求,这样可以节省很多请求。

image.png
image.png
image.png

应用场景

image.png

自己实现

场景

一个输入框,用户在上面输入后,就会发送请求(这里只是简单打印,表示发送了请求)
image.png
但是现在每次输入,都会发送请求。

解决方案

通过一个防抖 debounce函数,让用户输入完,等待一段时间后,再发送请求。

改成定义一个发送请求的函数,放入防抖函数中,给一个延迟(比如2000毫秒),然后再赋值给点击事件。
image.png
image.png

基本实现原理

通过setTimeout延迟执行传入的函数,如果再次触发,就判断当前队列有没有在等待执行的setTimeout函数,有的话就取消,然后执行setTimeout函数。
image.png

优化1:this指向

未优化前,this的指向是有问题的,inputChange函数定义的时候,this指向的是window,而debounce里面只是简单地在全局环境下调用,因此this指向的就是window。
但这种情况,this肯定是需要指向触发的那个HTML元素的。
image.png

而 debounce 函数调用的时候,是通过元素调用的,这个时候的this指向的是元素对象本身,是没问题的。

因此,只要在_debounce函数,调用fn的时候,把它的this通过apply的方式绑定 debounce 函数的this就可以了。
image.png

优化2:Event参数

元素的on事件执行的时候,会有一个默认的Event对象作为参数,未优化前,调用fn,是没有传入参数的,所以没办法获取这个Event

只要修改里面的参数,通过剩余参数的方式,接收元素on调用传入的Event就可以了,然后传给apply方法的第二个参数
image.png

优化3:立即执行一次

淘宝的输入框,在输入第一个字符时,会发送第一个请求开始联想,后续输入才防抖。
然后用户停止输入一段时间,发送请求后,再下一轮输入第一个又发送请求,后续继续防抖。

而不是第一个字符就防抖,增加用户的体验。

首先,给函数第三个参数,表示是否需要立即执行一次,默认是false。
然后外部给一个变量保存是否立即执行过。
如果需要立即执行,且没有第一次执行过,就立刻执行一次,然后改状态。
延迟执行后,改回状态,开始下一轮立即执行监听。
image.png

优化4:取消功能

image.png
用户可能在输入后,点击取消

可以给_debounce 函数封装一个取消功能,函数也是对象,也可以增加属性。
image.png
然后改下
image.png

增加取消按钮,给按钮增加点击事件,调用取消功能即可。
image.png

优化5:返回值(用的少)

假如要执行的函数,是有返回值的
image.png

方案1:多传一个参数,回调函数,用回调函数接收返回值
image.png
image.png

方案2:返回 Promise 对象,外面用.then( (res)=>{} ) 去接收返回的结果,可以和方案1共存
image.png
image.png

===============

节流 throttle函数

说明

image.png
image.png
image.png
image.png
image.png

应用场景

image.png

自己实现

场景

一个输入框,用户输入第一个字符开始发送一个请求(这里用打印当做发送请求),然后2秒内不再发送,接着用户再次输入才会再发送,再冷却2秒
image.png

解决方案

通过一个节流 throttle 函数,让用户输入完立刻发送请求,等待一段时间后,才能再发送请求。

改成定义一个发送请求的函数,放入节流函数中,给一个冷却时间(比如2000毫秒),然后再赋值给点击事件。

image.png

基本实现原理(简单的)

通过一个变量控制是否正在冷却,只有冷却完才能再次调用函数
image.png

优化1:this指向

未优化前,this的指向是有问题的,clickFn 函数定义的时候,this指向的是window,而 throttle 里面只是简单地在全局环境下调用,因此this指向的就是window。
但这种情况,this肯定是需要指向触发的那个HTML元素的。

而 throttle 函数调用的时候,是通过元素调用的,这个时候的this指向的是元素对象本身,是没问题的。

因此,只要在 _throttle 函数,调用fn的时候,把它的this通过apply的方式绑定 debounce 函数的this就可以了。
image.png

优化2:Event参数

元素的on事件执行的时候,会有一个默认的Event对象作为参数,未优化前,调用fn,是没有传入参数的,所以没办法获取这个Event

只要修改里面的参数,通过剩余参数的方式,接收元素on调用传入的Event就可以了,然后传给apply方法的第二个参数
image.png

优化3:触发时机

默认是用户按下时,开始触发,然后进入冷却。

但有时候需求是按下时不触发,冷却结束时触发;有时候是两者都需要有。

这个时候通过传入一个参数控制触发的时机即可。
image.png
image.png

优化4:返回值(用得少)

参考防抖的返回值

===============

第三方库

image.png
https://underscorejs.org/

image.png