JavaScript 中的防抖和节流,以及页面性能优化
前端页面中的防抖和节流其实和硬件上有关按钮防抖和的节流概念是相似的。
在硬件设计中,因为硬件的不完全一致性,用户在按压或者点按按钮的时候肯能会出现抖动,这个抖动反应在示波器上就是突然一个高电平或者低电平,所以需要开发者在硬件设计上,或者软件层面过滤掉这个波动,这个就是按钮的防抖。按钮的防抖在软件上处理的较多,一般默认一个按钮在一秒内用户不应该触发超过10次,所以防抖的设定便是在按钮按下的那一刻起,如果在50ms内出现了超过一次释放,则不处理,将其认为是抖动,知道大约100ms左右出现真正的释放信心再通过逻辑来判断是否为有有效点击。
这个过程应用在前端页面上,就是当用户通过鼠标或者键盘连续触发一些交互事件的时候,处理程序能够过滤掉一些无用的操作,减轻浏览器的负担,以便页面能够看起来更顺滑。
防抖
防抖是指用户交互的防抖,而不是页面视觉上的抖动。
举个例子,用户通过鼠标滚轮或者拖拽滚动条滚动页面的时候,会连续触发 Window 的 scroll 事件,或者用户重置浏览器页面尺寸的时候,也会连续触发 window 的 resize 事件,如果正好脚本对这两个事件之一有监听处理,那么就会存在短时间连续多次触发的问题,一般来说我们无需高频率的响应事件,所以就需要 防抖 。
由于防抖和节流不一定只应用在页面中,所以一般会将防抖和节流作为工具函数来使用,我这里也作为应用函数来定义下:
const utils = {
/**
* 防抖函数
* @param {function} cb 事件函数
* @param {number} delay 延时时间
*/
debounce: function (cb, delay) {
let timerHandle = null;
return function (...params) {
clearTimeout(timerHandle);
timerHandle = setTimeout(function () {
cb.call(this, ...params);
}, delay);
}
}
}
使用这个工具函数,由于 debounce 返回的是一个函数对象,所以:
function onScrollHandle (event) {
event = event || window.event;
cosnsole.log("window scroll");
}
// 监听 scroll 事件
window.addEventListener('scroll', debounce(onScrollHandle, 300));
点击下方的按钮可以开始防抖测试,请使用鼠标左键连续点击,如果两次点击事件的间隔小于 500ms ,将以最后一次触发的时间为准,最后一次点击 500ms 后将显示弹出提示。
节流
节流的概念与防抖有点类似,不同点在于防抖的目的是为了触发一次,而节流的目的是能连续触发。举个例子,比如有一个自动搜索框,如百度搜索栏,当我们在输入框中输入内容后,间隔一个较短的时候,就会自动触发关键词提示,当我们连续输入的时候,这个触发也会一直连续触发,这个就是节流的一种应用。
另一种应用,拿物联网中条件亮度的滑动条为例。假设现在Web端有一个页面,页面上有一个滑动条,滑动条的目的是当用户在滑动条上华东时,可以将滑动条的值通过 websocket 转发到设备上,但是当用户操作时滑动条的监听回调是连续多次触发的,如果每一次连续的触发都要给设备端发送亮度指令的话,这就造成了一点网络带宽的浪费,所以需要对这个事件进行 节流 ,以便节省带宽资源。
解决办法可以是这样的:当用户在滚动条上连续操作时,每 500ms 读取一次当前的值,然后将读到的值发送到设备端。这就避免了多次连续发生,节省了浏览器资源。
实现一下节流函数:
const utils = {
/**
* 节流函数
* @param {function} cb 事件函数
* @param {number} delay 响应周期
*/
throttle: function (cb, delay) {
let timerHandle = null;
return function (...params) {
if (timerHandle !== null) return;
timerHandle = setTimeout(function () {
cb.call(this, ...params);
timerHandle = null;
}, delay);
}
}
}
下面是测试按钮,可以连续点击。
连续点击上方按钮,可以看到弹出层会以 500ms 左右的间隔连续显示和消失。
页面性能优化
基于防抖和节流,可以在应用层对页面的交互进行优化,这里又说到优化,之前有一篇文章从 HTML 、 CSS 和 JavaScript 三个方面介绍过基本的优化方案,但实际上有很多优化方案都是在引用上做的,并不会可以的在 HTML 或者 CSS 上做太多文章,原因也很简单,就是需要保持项目的可读性和可维护性,不能单纯因为追求几个毫秒的提升而放弃可读性。
从节流和防抖的角度来说,使用节流和防抖来做页面优化是站在应用的角度来讲的,虽然浏览器框架和事件循环机制允许不做节流和防抖,但做了这方面优化的性能提升实则更显著,首先是不用频繁响应无用事件,假如存在网络应用,也可以通过节流来缩减请求,减少不必要的贷款浪费。
除了以上两种之外,还有一种常见的应用层优化就是懒加载,也是从减少请求和节省贷款的角度来做优化,以上这些知识思路,实际开发中会有更多的应用上的方案。