节流和防抖
在前端开发中,有时为了性能
考虑,会限制在某一段时间内频繁执行的任务的次数,防止程序开销过大引发卡顿或崩溃的情况,一种常用的手段就是节流和防抖。但这两者颇有些相似,导致一些初学者常常弄混,导致用错,本篇将对这两者的概念进行区分和说明。
节流
有一个成语,叫开源节流,这里节流的意思是指节省开支
,那如何节省开支呢?拿我们日常生活中的例子来说,假如一个家庭每周都会去电影院消费一次,但由于最近丈夫失业,导致收入巨减,为了平衡收支,家庭成员决定,不能每周去电影院消费了,改为每月去一次。通过这样的方式来减少了日常开支,达到节流的目的。
对于程序中的节流而言,其目的和功能是一样的,我们来看一个例子:
<div id="myDiv"
style="height: 150px; line-height:150px; text-align:center; color: #fff; background-color:#ccc; font-size:80px;">
</div>
JavaScript代码如下:
let num = 1
const content = document.getElementById('myDiv')
function count() {
content.innerHTML = num++
}
content.onmousemove = count
在上述代码中,div 元素绑定了 mousemove 事件,当鼠标在 div 区域移动的时候,会持续地去触发事件,导致频繁执行count函数。假如count函数是一个开销很大的任务,那么如此频繁的执行很可能导致页面卡顿甚至崩溃,为了解决这个问题,那么,节流就派上用场了:
<script src='./lodash.min.js'></script>
content.onmousemove = _.throttle(count, 2000)
也就是说,不管鼠标在 div 区域移动如何快速移动,每2s内只会执行一次count函数。这么说吧,如果鼠标一直在div 区域移动,之前10s内可能会执行count函数500次左右(大约20ms执行一次),而节流后,只会执行5次了,开销减少了100倍。
总结一下,所谓节流,就是指连续触发事件,但是在 n 秒中只执行一次函数。
防抖
先来说说什么是抖动,不知道大家坐过那种减震效果不好的拖拉机
或者公交车
没有,尤其是当司机起步时,那种持续的抖动感,那就是抖动,也就是说,在一段时间内,会持续而频繁地执行一些动作。那么防抖呢?就是要防止这么频繁的抖动,那要怎么做呢?
可以设置一种过滤抖动
的装置,限制抖动的频率,比如,在2s内最多让它抖动一次,有人可能疑惑了,这看上去不是和节流一样吗?其实不然,还是上面的例子,我们来看看防抖:
content.onmousemove = _.debounce(count, 2000)
用了防抖后,如果在2s内一直有鼠标在移动,那么必须等待最后一次移动延迟2s后,才会执行count函数,比如,在开始时鼠标移动了一次,在1.5s时鼠标又移动了一次,那么在3.5s时才会执行第一次count函数;如果在开始时鼠标移动了一次,在1.5s时鼠标又移动了一次,之后,在3.4s时鼠标又再次移动了一次,那么在第5.4s时才会执行第一次count函数。
对比够明显了吧,可以说,防抖是一种更严格
的节流形式。
实际应用
明白了节流和防抖的区别后,那么在前端开发的实际应用中,什么时候用节流,什么时候用防抖呢?
我们来看一个场景,如果需要在滚动页面
时执行一项开销较大的任务,因为滚动时会频繁触发onscroll事件,导致该任务被频繁执行,引起了页面的卡顿,为了减少触发次数,提高性能,那使用节流或者防抖都可以达到提高性能的目的。
但如果除了提升性能外,还需要记录用户稳定滚动的次数,比如1s内用户没有再次滚动才算一次,那么,就只能使用防抖来做了。
另外,一种常用的使用防抖的场景是,当用户在input
框中输入字符进行后端查询时,如果每输入一个字符,前端就请求一次后端接口,这无疑对后端接口带来性能压力,为了优化体验,一般都会加一个防抖机制,比如,500ms内用户没有额外的输入操作,就表示用户的输入已经稳定,才发起一次后期请求,将结果展示到页面上。
小结
本篇主要从宏观上对节流和防抖的概念进行了区分和说明,关于更多技术细节,可以参考后面的参考部分。