函数防抖与节流
在进行窗口的resize、scroll,输入框内容校验等操作时,如果事件处理函数调用的频率无限制,会加重浏览器的负担,导致用户体验非常糟糕。此时我们可以采用debounce(防抖)和throttle(节流)的方式来减少调用频率,同时又不影响实际效果。
函数防抖(debounce)
函数防抖(debounce):
当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。如下图,持续触发scroll事件时,并不执行handle函数,当1000毫秒内没有触发scroll事件时,才会延时触发scroll事件。
在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:
- 如果在200ms内没有再次触发滚动事件,那么就执行函数
- 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时
效果:
如果短时间内大量触发同一事件,只会执行一次函数。
实现:
函数防抖的基本思想是设置一个定时器,在指定时间间隔内运行代码时清楚上一次的定时器,并设置另一个定时器,知道函数请求停止并超过时间间隔才会执行。,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现。
使用场景:
文本框输入搜索(连续输入时避免多次请求接口)
防抖debounce代码:
/**
* 防抖函数
* @param {Fcuntion} fn 要执行的函数
* @param {Number} delay 延迟执行的毫秒数,默认是200毫秒
* @return {Function} 防抖函数
*/
function debounce(fn, delay) {
var timer = null; //借助闭包
var delay = delay || 200;
return function() {
var args = arguments;
var that = this;
// 清楚上一次的定时器
if(timer){
clearTimeout(timer)
}
timer = setTimeout(function() {
fn.apply(that,args);
}, delay);
}
}
// 处理函数
function handle(str){
console.log('write---',str,Date.now());
}
// 监听input输入change事件
// 注意:如果防抖的函数不需要参数的话,可以使用第一种写法防抖,如果需要防抖的函数还需要传入参数,请使用第二种写法。
//防抖第一种写法:
$('input').on('input',debounce(handle,2000));
//防抖第二种写法:
var debounced = debounce(handle,2000);
$('input').on('input',function(){
debounced($(this).val());
});
防抖函数(来自uView2.0源码):
let timeout = null
/**
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function debounce(func, wait = 500, immediate = false) {
// 清除定时器
if (timeout !== null) clearTimeout(timeout)
// 立即执行,此类情况一般用不到
if (immediate) {
const callNow = !timeout
timeout = setTimeout(() => {
timeout = null
}, wait)
if (callNow) typeof func === 'function' && func()
} else {
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
timeout = setTimeout(() => {
typeof func === 'function' && func()
}, wait)
}
}
export default debounce
当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。
函数节流(throttle)
函数节流(throttle):
当持续触发事件时,保证一定时间段内只调用一次事件处理函数。规定在一个单位时间内,只能触发一次函数,如果这个单位时间内触发多次函数,只有一次生效; 典型的案例就是鼠标不断点击触发,规定在n秒内多次点击只有一次生效。
效果:
如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。
实现原理:
其原理是用时间戳来判断是否已到回调该执行时间,记录上次执行的时间戳,然后每次触发 scroll 事件执行回调,回调中判断当前时间戳距离上次执行时间戳的间隔是否已经到达 规定时间段,如果是,则执行,并更新上次执行的时间戳,
使用场景
resize、scroll、mousemove等事件触发监听
节流throttle代码:
/**
* 配置节流函数
* @param {Function} fn 要执行的函数
* @param {Number} delay 延迟执行的毫秒数,默认是200毫秒
* @return {Function} 节流函数
*/
function throttle(fn, delay) {
// 上一次函数触发时间
var lastTime;
var timer = null;
var delay = delay || 200;
return function() {
// 记录当前函数触发的时间
var nowTime = Date.now();
var context = this;
var args = arguments;
if (lastTime && nowTime - lastTime < delay) {
// 如果上一次函数触发时间存在,并且现在触发时间与上一次触发时间差值小于delay
// 说明触发时间太短,还没有到达规定的delay时间
// 所以先清除上一次的定时器,重新设置延迟执行
clearTimeout(timer);
timer = setTimeout(function(){
// 记录上一次函数触发的时间
lastTime = nowTime;
fn.apply(context, args);
}, delay);
} else {
lastTime = nowTime;
fn.apply(context, args);
}
}
}
// 处理函数
function handle(id){
console.log('aa---',id,Date.now());
}
// 监听window的scroll事件
// 注意:如果节流的函数不需要参数的话,可以使用第一种写法节流,如果需要节流的函数还需要传入参数,请使用第二种写法。
//节流第一种写法:
$(window).on('scroll',throttle(handle, 3000));
//节流第二种写法:
var throttled = throttle(aa,2000);
$(window).on('scroll', function(){
throttled(99)
});
节流函数(来自uView2.0源码):
let timer; let
flag
/**
* 节流原理:在一定时间内,只能触发一次
*
* @param {Function} func 要执行的回调函数
* @param {Number} wait 延时的时间
* @param {Boolean} immediate 是否立即执行
* @return null
*/
function throttle(func, wait = 500, immediate = true) {
if (immediate) {
if (!flag) {
flag = true
// 如果是立即执行,则在wait毫秒内开始时执行
typeof func === 'function' && func()
timer = setTimeout(() => {
flag = false
}, wait)
}
} else if (!flag) {
flag = true
// 如果是非立即执行,则在wait毫秒内的结束处执行
timer = setTimeout(() => {
flag = false
typeof func === 'function' && func()
}, wait)
}
}
export default throttle
总结
函数防抖(debounce):将几次操作合并为一此操作进行。原理是维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触发的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发。
函数节流(throttle):使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。
区别: 函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。 比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次 Ajax 请求,而不是在用户停下滚动页面操作时才去请求数据。这样的场景,就适合用节流技术来实现。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具