这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战
防抖与节流函数是一种最常用的 高频触发 优化方式,能对性能有较大的帮助。
两种优化方式有很多实现方法,本篇只介绍几种实现思路。
更多文章在我的 Github 及个人公众号【全栈道路】上,欢迎观赏【一个不知名的足球狗的前端知识点】,如有受益,不要钱,小手点个Star。
阅读本文您将收获
- 防抖的原理和部分实现方式
- 节流的原理和部分实现方式
写在前面
- 前端工程师在开发过程中会经常处理事件,例如
click
、onChange
、resize
事件等等,但当我们监听如scroll
、onChange
等事件时,会发现这些事件触发非常频繁。 - 举个栗子,当我们在监听浏览器页面滚动事件时,往往一次用户滚轮的滚动事件会触发多次,一旦我们在回调中处理了DOM操作,多次的回流重绘必然会对浏览器的性能造成影响,轻则浏览器掉帧,影响用户体验,重则浏览器崩溃。
- 那么我们怎么去解决这种问题呢,好的方法就是我们把这些高频操作的频次降低,或者把多次的操作合并成一次回调执行,防抖和节流正是解决这种问题的好方式。
防抖
- 防抖 (debounce): 将多次高频操作优化为只在最后一次执行。
- 原理:在事件被触发n秒后,再去执行回调函数。如果n秒内该事件被重新触发,则重新计时。结果就是将频繁触发的事件合并为一次,且在最后执行。
- 使用场景:用户输入,只需再输入完成后做一次输入校验即可。
// 简版防抖函数
var timer = false;
function(){
clearTimeout(timer); // 清除未执行的代码,重置回初始化状态
timer = setTimeout(function(){
console.log("函数防抖");
}, 300);
};
// 高级版函数防抖
function debounce(fn, wait, immediate) {
// timer用来记录当前函数执行状态
let timer = null
return function() {
// 利用this和arguments获取作用域和变量
let args = arguments
let context = this
if (immediate && !timer) {
fn.apply(context, args)
}
// 清理掉正在执行的函数并重新执行
if (timer) clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
节流
- 节流(throttle): 每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作。
- 原理:规定一个时间n,n秒内,将触发的事件合并为一次并执行。
- 使用场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms执行一次即可。
// canRun函数 执行状态
var canRun = true;
function throttle(){
if(!canRun){
// 函数如果在执行中,则直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函数节流");
canRun = true;
}, 300);
};
function throttle(fn, cycle) {
let start = Date.now();
let now;
let timer;
return function () {
now = Date.now();
clearTimeout(timer);
if (now - start >= cycle) {
fn.apply(this, arguments);
start = now;
} else {
timer = setTimeout(() => {
fn.apply(this, arguments);
}, cycle);
}
}
}
写在最后
如果你觉得这篇文章对你有益,烦请点赞以及分享给更多需要的人!
欢迎关注【全栈道路】及微信公众号【全栈道路】,获取更多好文及免费书籍!
有需要【百度】&【字节跳动】&【京东】&【猿辅导】内推的也请留言哦,你将享受VIP级极速内推服务~