在前端开发中,有时候一些事件会因为触发过于频繁而导致的性能问题。当前事件还没有处理完,下一个相同的事件又被触发,严重的情况下会导致出现延迟、页面卡顿甚至崩溃。下面介绍两种解决这种问题的方法:防抖与节流。
防抖
使用一个setTimeout定时器来对需要优化的函数进行延迟执行。让事件在某个延迟的时间内只执行一次。
具体思路
- 事件在第一次触发时,先延迟时间N
- 如果在N内没有重复触发该事件,那么直接执行该事件。
- 如果在N内重复触发了该事件,那么将该定时器清零,重新开始计时。
//防抖函数
function debounce(fn, delay) {
let timer = null;
return function(...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(()=>{
fn.apply(this,args);
},delay);
}
}
function handle(){
console.log("执行事件");
}
//滚动事件
window.addEventListener('scroll',debounce(handle,500));
节流
规定一定时间内只能触发一次事件处理函数。即使函数在短时间内被触发多次,也只能有一次生效。
实现方法
主要三种实现方法:时间戳,定时器,时间戳+定时器
时间戳
在第一次触发事件时记录下当前的时间,并且执行一次回调函数。然后,在这之后函数每隔N时间执行一次,在小于N时,该事件是不执行的,分别以当前时间和上一个 事件执行的时间进行时间差的对比。
//节流函数(时间戳)
var throttle = function (fn, delay) {
var prev = Dta.now();
return function () {
var context = this;
var args = arguments;
var now = Data.now();
if(now - prev >= delay) {
fn.apply(context,args);
prev = Data.now();
}
}
}
function handle(){
console.log("执行事件");
}
// 滚动事件
window.addEventListener('scroll',throttle(handle. 500));
定时器
在触发事件时,设置一个定时器,当再次触发该事件时,如果定时器存在则会不执行,只有到延时的N时间后,定时器才会执行该函数,同时执行之后清空定时器,等待下一个流程进行循环。
var throttle = function (fn, delay) {
var timer = null;
return function () {
var context = this;
var args = arguments;
if(!timer) {
timer = setTimerout(()=>{
fn.apply(context, args);\
timer = null;
},delay);
}
}
}
function handle() {
console.log("执行事件");
}
window.addEventListener('scroll', throttle(handle,500));
时间戳+定时器
在节流函数内部记录开始时间(startTime),当前时间(curTime)和剩余时间(remaining),当剩余时间小于等于0时则可以执行处理函数,可以保证第一次触发函数就可以立即执行,并且之后每隔N时间执行一次。 如果还没有到时间,则会在剩余时间后触发,保证最后一次触发时间也可以执行函数。 如果在剩余时间内再次触发事件,取消当前的定时器,并重新计算一个剩余时间来判断当前的状态。
var throttle = function (fn, delay) {
var timer = null;
var startTime = Date.now();
return function (){
var curTime = Date.now();
var remaining = delay - (curTime - startTime);
var context = this;
var args = arguments;
clearTimeout(timer);
if(remaining <= 0) {
fn.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(fn, remaining);
}
}
}
function handle(){
console.log("执行事件");
}
window.addEventListener('scroll', throttle(handle, 500));