问题1: 若是实现了dom拖拽功能,可是在绑定拖拽事件的时候发现每当元素稍微移动一点便触发了大量的回调函数,致使浏览器直接卡死,这个时候怎么办?javascript
**问题2:**若是给一个按钮绑定了表单提交的post事件,可是用户有些时候在网络状况极差的状况下屡次点击按钮形成表单重复提交,如何防止屡次提交的发生?vue
为了应对如上场景,便出现了函数防抖和函数节流两个概念,总的来讲:java
这两个方法是在时间轴上控制函数的执行次数。git
概念: 在事件被触发n秒后再执行回调,若是在这n秒内又被触发,则从新计时。
github
生活中的实例: 若是有人进电梯(触发事件),那电梯将在10秒钟后出发(执行事件监听器),这时若是又有人进电梯了(在10秒内再次触发该事件),咱们又得等10秒再出发(从新计时)。
segmentfault
概念: 规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,若是在同一个单位时间内某事件被触发屡次,只有一次能生效。
浏览器
生活中的实例: 咱们知道目前的一种说法是当 1 秒内连续播放 24 张以上的图片时,在人眼的视觉中就会造成一个连贯的动画,因此在电影的播放(之前是,如今不知道)中基本是以每秒 24 张的速度播放的,为何不 100 张或更可能是由于 24 张就能够知足人类视觉需求的时候,100 张就会显得很浪费资源。
网络
假设,咱们观察的总时间为10秒钟,规定1秒做为一次事件的最小间隔时间。闭包
0.5s/次
,那么函数防抖如图 app
由于始终无法等一秒钟就被再次触发了,因此最终没有一次事件是成功的。
函数节流如图
由于控制了最多一秒一次,频率为0.5s/次
,因此每一秒钟就有一次事件做废。最终控制成1s/次
2s/次
,那么函数防抖如图
2s/次
已经大于了规定的最小时间,因此每计时两秒便触发一次。
函数节流如图
一样,2s/次
大于了最小时间规定,因此每一次触发都生效。
对于函数防抖,有如下几种应用场景:
scroll
是否滑到底部,滚动事件
+函数防抖
总的来讲,适合屡次事件一次响应的状况
对于函数节流,有以下几个场景:
总的来讲,适合大量事件按时间作平均分配触发。
function debounce(fn, wait) {
var timer = null;
return function () {
var context = this
var args = arguments
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
fn.apply(context, args)
}, wait)
}
}
var fn = function () {
console.log('boom')
}
setInterval(debounce(fn,500),1000) // 第一次在1500ms后触发,以后每1000ms触发一次
setInterval(debounce(fn,2000),1000) // 不会触发一次(我把函数防抖看出技能读条,若是读条没完成就用技能,便会失败并且从新读条)
复制代码
之因此返回一个函数,由于防抖自己更像是一个函数修饰,因此就作了一次函数柯里化。里面也用到了闭包,闭包的变量是timer
。
function throttle(fn, gapTime) {
let _lastTime = null;
return function () {
let _nowTime = + new Date()
if (_nowTime - _lastTime > gapTime || !_lastTime) {
fn();
_lastTime = _nowTime
}
}
}
let fn = ()=>{
console.log('boom')
}
setInterval(throttle(fn,1000),10)
复制代码
如图是实现的一个简单的函数节流,结果是一秒打出一次boom
函数防抖和函数节流是在时间轴上控制函数的执行次数。防抖能够类比为电梯不断上乘客
,节流能够看作幻灯片限制频率播放电影
。