js中的很多事件,如scroll事件、resize事件、鼠标事件(mousemove、mouseover等)、
键盘事件(keyup、keydowm等)都存在被频繁触发的问题
频繁触发回调导致大量计算会引发页面抖动甚至卡顿,因此我们必须用一些手段来控制事件被触发的频率–
事件节流(throttle)和事件防抖(debounce)
节流与防抖
这两个东西都以闭包的形式存在,通过对事件对应的回调函数进行包裹、以自由变量的形式缓存时间信息,最后用setTimeout来控制事件的触发频率
Throttle:第一次为准
核心思想:在某段事件内,不管触发多少次回调,都以这段时间内的第一次为准,即在一段时间内无视后来产生的回调请求
实际交互:用户触发了一次srcoll事件,我们就为这个触发操作开启计时器,直到这段时间到了,第一次触发的scroll事件对应的回调才会执行,这段时间其他scroll的回调都会被无视
1 | // fn是我们需要包装的事件回调, interval是时间间隔的阈值 |
debounce: 最后一次为准
核心思想:某段时间内,不管触发多少次回调,都只认最后一次
实际交互:用户每次触发scroll事件都会清除当前计时器,重新计时间
1 | function debounce(fn, delay) { |
用throttle来优化debounce
想象一下,如果用户操作十分频繁–每次都不等debounce设置的delay就进行下一次触发
每次都重新生成定时器,回调函数一直被延迟,用户同样会觉得页面卡死
因此debounce需要一个“底线”,我们可以结合throttle的思想,设定一个原则:
delay时间内,重复触发可以重新生成定时器,delay时间到了,必须要给用户一个相应
这种结合版的思路,已经应用到很多成熟的前端库,作为加强版throttle函数的实现:
1 | function upThrottle(fn, delay) { |
应用
优化图片懒加载
1 | const imgs = document.querySelectorAll('.pic'); |