防抖与节流,看了些博客以及大厂的面试题,为一个高频考点。先对其做个总结,再将它写入实际上的目前在做的项目之中。
首先,为什么要使用防抖函数?
举一个实例来说,比如我们在某个搜索框中,比如我们想要搜索“apple”:
当我们输入a的时候,为了更好的用户体验,通常会出现对应的联想内容,这些联想内容通常是保存在服务器的,所以需要一次网络请求;
当继续输入ap的时候,再次发送网络请求;
那么apple总共需要发出5次网络请求,这会大大地损耗整个系统的性能,无论是对前端的事件处理或是对于服务器的压力。实际上,我们不需要这么多次的网络请求,正确的做法应该是,在合适的情况下再去发送网络请求。
比如说,如果用户快速的输入“apple”,那么只是发送一次网络请求,如果用户是输入a后想了一会儿,那这个时候a确实应该发送一次网络请求。简而言之,就是应该监听用户在某个时间段内,没有再次触发时,再去发送网络请求。
防抖的操作即为,只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数。
当事件触发时,相应的函数并不会被立即触发,而是会等待一定时间;当事件密集触发时,函数的触发会被频繁的延迟,只有等呆了一段时间也没有事件触发,才会真正的执行响应函数。
防抖的应用场景还是很多的,比如:
1.输入框中频繁地输入内容,搜索或者提交信息。
2.频繁地点击按钮,触发某个事件。
3.监听浏览器滚动事件,完成某些特定操作。
4.用户缩放浏览器地resize事件。
那么,节流是怎样呢?
预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。节流的操作即为,在某个时间内,某个函数只能被触发一次。
节流的应用场景为:
1.监听页面的滚动事件。
2.鼠标移动事件。
3.用户频繁点击按钮操作。
4.游戏中的一些设计。
总而言之,依然是密集的事件触发,然而相比于防抖函数,节流不会等待最后一次才去进行函数调用,而是会按照一定的频率进行调用。
本次项目中,使用到了防抖函数,因为之前,我们监听goodsitem的时候,使用事件总线的时候,在home.vue中执行了:
mounted() { //3.监听item中图片加载完成 this.$bus.$on("itemimageload",()=>{this.$refs.scroll.refresh() }) }
由于主页面需要加载的商品页面比较多,频繁调用对性能无好处。因此,我在这里使用了一个防抖函数。防抖的话,我先把它封装了,代码如下:
export function debounce(func,delay){ let timer = null return function (...args){ if (timer) clearTimeout(timer) timer = setTimeout(()=>{ func.apply(this,args) },delay) } }
下面我们来,解析下上述的防抖函数。其核心思路如下:
1.当触发一个函数时,并不会立即执行这个函数,而是会延迟(通过定时器来延迟函数的执行)。
2.如果在延迟时间内,又重新触发函数,那么取消上一次的函数执行,即取消定时器。
3.如果在延迟时间内,没有重新触发函数,那么这个函数就会正常执行(执行传入的函数)。
将思路转成代码即可:
定义debounce函数要求传入两个函数:需要处理的函数func以及延迟时间。
通过定时器来延迟传入函数func的执行,如果在此期间有再次触发这个函数,那么clearTimeout取消这个定时器,如果没有触发,那么在定时器的回调函数中执行即可。
那么,接下来我们可以改动在home.vue中的代码啦~
先导入debounce函数,
import {debounce} from "../../src/components/common/utils/utils";
之后再改动mounted:
mounted() { const refresh = debounce(this.$refs.scroll.refresh, 200) this.$bus.$on("itemimageload", () => { refresh() }) }