通常在项目中咱们会对input、scroll、resize等事件进行节流控制,防止事件过多触发,减小资源消耗;在vue的官网的例子中就有关于lodash的debounce方法的使用,当时也提到了throttle,但一直没搞明白节流 throttle 与 去抖 debounce具体区别在哪里,因此花了点时间来搞清楚。css
节流 throttle 与 去抖 debounce的区别主要在触发时机上:html
debounce(func, wait, options)
:建立并返回函数的防反跳版本,将延迟函数的执行(真正的执行)在函数最后一次调用时刻的wait毫秒以后,对于必须在一些输入(可能是一些用户操做)中止以后再执行的行为有帮助。将一个连续的调用归为一个,若是连续在wait毫秒内调用,最后只有最后一次会执行throttle(func, wait, options)
:建立并返回一个像节流阀同样的函数,当重复调用函数的时候,最多每隔指定的wait毫秒调用一次该函数;不容许方法在每wait毫秒间执行超过一次,若是连续在wait毫秒内调用,最后执行会均匀分布在大约每wait一次对于lodash来讲,throttle是调用debounce来实现的,throttle 和 debounce 最终都会都会调用 debounce 方法。当调用 _.debounce
lodash会返回一个函数,这个函数在被调用时会生成一个 setTimeout(delayed, delay)。其中 delayed 又是一个内部方法,在 delayed 被调用时进行以下检测:当前时间 - 上次func被调用事件 是否 小于 0 或 大于 delay ?若是是则执行一次 func,记录并返回执行结果,同时更新上次被调用时间;若是不是则调用 setTimeout 进行下一次的判断。_.throttle
方法只不过是多给 debounce 传了一个 options = {maxWait: $maxWait, leading: true, trailing: true}
,这个选项的意思是至少保证在每 maxWait 时间让 func 被调用一次。前端
能够看下面的栗子:vue
这个图中图中每一个小格大约30ms,右边有原生mouseover事件、lodash与jQuery节流去抖插件的debounce与throttle事件。
在图左区域移动鼠标时:对于debounce,mouseover事件一直没有被调用,直到停下来才被调用一次。而throttle是每wait毫秒就调用一次。jquery
debounce:第一次触发后,进行倒计wait毫秒,若是倒计时过程当中有其余触发,则重置倒计时;不然执行。用它来丢弃一些重复的密集操做,直到流量减慢。
throttle:第一次触发后先执行fn(lodash能够经过{leading: false}
来取消),而后wait ms后再次执行,在单位wait毫秒内的全部重复触发都被抛弃。即若是有接二连三的触发,每wait ms执行fn一次,用在每隔必定间隔执行回调的场景。ajax
按照上面的说明,去抖就是连续屡次delay内的操做取最后一次操做真正执行。微信
let reduceEvent function debounce(cb, delay) { if (!reduceEvent) { reduceEvent = setTimeout(() => { cb() console.log('执行啦!!') reduceEvent = null }, delay) } } setTimeout(() => debounce(() => console.log(1), 2000), 1000) // 打印: 1 执行啦!! setTimeout(() => debounce(() => console.log(2), 2000), 2000) setTimeout(() => debounce(() => console.log(3), 2000), 2000) setTimeout(() => debounce(() => console.log(4), 2000), 4000) // 打印: 4 执行啦!!
按照上面的说明,节流就是连续屡次delay内的操做按照指定的间隔来执行。app
function throttle(func, wait = 200) { let last = 1 let timer return function(...rest) { const now = +new Date() if (last && now - last < wait) { clearTimeout(timer) timer = setTimeout(() => { last = now func.apply(this, rest) }, wait) } else { last = now func.apply(this, rest) clearTimeout(timer) } } } const task = throttle(() => console.log(1), 2000) setTimeout(task, 0) setTimeout(task, 500) setTimeout(task, 1000) setTimeout(task, 2000) // 打印: 1 1
网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~ide
参考:函数
PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~
另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~