前端性能优化(一)——浅谈节流与防抖
前言
本着总结、自我提高为目的,整理了下自己认知的前端性能优化方面的方式方法。本文主要介绍最普遍的优化之一 ——节流和防抖。
使用背景
频繁触发回调导致的大量计算会引发页面的抖动甚至卡顿。为了规避这种情况,我们需要一些手段来控制事件被触发的频率。
无论是节流还是防抖,都是以“闭包“的形式存在,以自由变量的形式缓存时间信息,最后用 setTimeout 来控制事件的触发频率
Throttle(节流)
所谓节流,可以理解成第一个人说得算,在一定时间内无论你触发多少次函数,我都以第一次触发为标准,并且在时间结束后给予反馈。话不多说,以scroll事件为例,直接看代码!
// fn是我们需要包装的事件回调, interval是时间间隔
function throttle(fn, interval) {
// last为上一次触发回调的时间
let last = 0
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last >= interval) {
// 如果时间间隔大于我们设定的时间间隔阈值,则执行回调
last = now;
fn.apply(context, args);
}
}
}
// 用throttle来包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
总结下来,所谓节流就是在一段时间内无视后来产生的回调请求
Debounce(防抖)
所谓防抖,就是像是一个“傻瓜”,*它会一直等你到底。也就是在一段时间内,不管你触发了多少次回调,我都只认最后一次。 还是以最scroll事件为例,直接看代码
function debounce(fn, delay) {
// 定时器
let timer = null
// 将debounce处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 每次事件被触发时,都去清除之前的旧定时器
if(timer) {
clearTimeout(timer)
}
// 设立新定时器
timer = setTimeout(function () {
fn.apply(context, args)
}, delay)
}
}
// 用debounce来包装scroll的回调
const better_scroll = debounce(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
节流+防抖
防抖是有些问题的,问题就在于它“太傻”了。只能痴痴地等待。我们可以用节流去优化一下防抖。同样是以scroll 为例,看代码
// fn是我们需要包装的事件回调, delay是时间间隔的阈值
function throttle(fn, delay) {
// last为上一次触发回调的时间, timer是定时器
let last = 0, timer = null
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this
// 保留调用时传入的参数
let args = arguments
// 记录本次触发回调的时间
let now = +new Date()
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer)
timer = setTimeout(function () {
last = now
fn.apply(context, args)
}, delay)
} else {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now
fn.apply(context, args)
}
}
}
// 用新的throttle包装scroll的回调
const better_scroll = throttle(() => console.log('触发了滚动事件'), 1000)
document.addEventListener('scroll', better_scroll)
小节
正好最近刚换好工作, 越发发现性能优化方面,尤其是节流防抖已经成为前端面试的高频考点。我觉得本文写到的代码,除了要看懂、理解过程外,最重要的是要在平时开发中进行应用。用了之后,我相信你会感叹道:“嗯,真香。”
我就是我,全网最菜的前端——痴心。有缘下次更新见。