我有一个牛逼的防抖,你要不要学
在开发中,我们可能碰到这样的问题:
-
用户在搜索的时候,在不停的输入,如果每敲一个字我们就要调一次接口去查询,接口调用太频繁,会占内存给卡住。
-
手机号、邮箱验证输入检测
-
窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
-
页面滚动处理事件
原理分析
防抖:在事件被触发 n 秒后再执行回调函数,如果在这 n 秒内又被触发,则重新计时延迟时间
函数防抖原理:通过维护一个定时器,其延迟计时以最后一次触发为计时起点,到达延迟时间后才会触发函数执行。
防抖的实现方式分两种 “立即执行” 和 “非立即执行” ,区别在于第一次触发时,是否立即执行回调函数。
“立即执行防抖” 指事件触发后,回调函数会立即执行,之后要想触发执行回调函数,需等待 n 秒延迟
”非立即执行防抖“ 指事件触发后,回调函数不会立即执行,会在延迟时间 n 秒后执行,如果 n 秒内被调用多次,则重新计时延迟时间
理解:
-
相当于英雄大招,施法后要等技能冷却才能再次施法(立即执行)。
-
法师发技能的时候要读条,技能读条没完再按技能就会重新读条(非立即执行)。
手写防抖
那么理解了什么是防抖,我们可以手写一个防抖,这不仅在面试中经常出现,工作中也会遇到。
非立即执行
<body>
<button id="debounce">点击</button>
<script>
window.onload=function(){
var mydebounce = document.getElementById("debounce")
mydebounce.addEventListener("click",debounce(sayDebounce,1000))
}
//防抖函数
function debounce(fn,time) {
let timer = null
return function () {
let context = this
if(timer) clearTimeout(timer) //清除前一个定时器
timer = setTimeout(()=>{ //在时间间隙内再次点击不会执行fn函数
fn.apply(context,arguments)
},time || 500)
}
}
//要防抖的事件处理
function sayDebounce() {
console.log("处理防抖的事件写在这里,比如发送请求");
}
</script></body>
特别说明:apply 是为了改变某个函数运行时的 context 即上下文而存在的,说人话就是改变this指针的指向,函数.apply(第一个参数就是你想吧this指针指向哪,第二个参数就是你向里面传的参数(arguments));
apply()方法接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
call()方法第一个参数和apply()方法的一样,但是传递给函数的参数必须列举出来。
在js中,所有的函数再被调用的时候都会默认传入两个参数,一个是this,还有一个是arguments。在默认情况下this都是指当前的调用函数的对象。但是有时候我们需要改变this的指向,也就是说使函数可以被其他对象来调用,那么我们应该怎样做呢?这时候我们就可以使用call和apply方法了;
但是问题来了,我不想点击了按钮要等一秒它才发起请求,It is too slow!能不能点击立即执行,再次点击才需要等待技能冷却?Of course!
立即执行
function debounce(fn,time) {
let timer = null
return function () {
let context = this
let args = arguments
if(timer) clearTimeout(timer) //清除前一个定时器
let callNow = !timer
timer = setTimeout(()=>{
timer = null
},time || 500)
if (callNow) fn.apply(context,args)
}
}
这个时候产品经理又提了一个新需求:能不能这个按钮立即执行,那个按钮非立即执行?
”呵......我早就猜到你会提出这种无理的需求!看剑!“,
可以实现吗?”可以,得加钱💴“。那我加个 immediate
参数判断是否立即执行呗。
组合版本
<body>
<button id="debounce">点击</button>
<script>
window.onload=function(){
var mydebounce = document.getElementById("debounce")
mydebounce.addEventListener("click",debounce(sayDebounce,1000,false))
}
//防抖函数
function debounce(fn,time,immediate) {
let timer = null
return function () {
let context = this
let args = arguments
if(timer) clearTimeout(timer) //清除前一个定时器
if (immediate) { //为true立即执行
let callNow = !timer
timer = setTimeout(()=>{
timer = null
},time || 500)
if (callNow) fn.apply(context,args)
}
else { //非立即执行
timer = setTimeout(function(){
fn.apply(context, args)
}, time || 500);
}
}
}
//要防抖的事件处理
function sayDebounce() {
console.log("处理防抖的事件写在这里,比如发送请求");
}
</script>
</body>
产品经理:”可不可以.......“, ”你走啊😠“
”能不能取消debounce
函数,比如在登录时候的重新请求短信验证码,错一次要等好久“
取消debounce(终极版)
<body>
<button id="debounce">点击</button>
<button id="dd">取消</button>
<script>
var mydebounce = document.getElementById("debounce")
var Mydebounce = document.getElementById("dd")
var set = debounce(sayDebounce,5000,true)
mydebounce.addEventListener("click",set)
Mydebounce.addEventListener("click",function () {
set.cancel()
} )
//防抖函数
function debounce(fn,time,immediate) {
let timer = null
let debounced = function () {
let context = this
let args = arguments
if(timer) clearTimeout(timer) //清除前一个定时器
if (immediate) { //为true立即执行
let callNow = !timer
timer = setTimeout(()=>{
timer = null
},time || 500)
if (callNow) fn.apply(context,args)
}
else { //非立即执行
timer = setTimeout(function(){
fn.apply(context, args)
}, time || 500);
}
}
debounced.cancel = function() { //取消防抖
clearTimeout(timer);
timer = null;
};
return debounced
}
//要防抖的事件处理
function sayDebounce() {
console.log("处理防抖的事件写在这里,比如发送请求");
}
</script>
</body>
面试官:你能手写一个防抖看看吗?
”看我不秀死你“
更多技术
https://mp.weixin.qq.com/s/GWWBm99rjWBcsgIGXyBwig
前端技术导航大全地址:
https://webstatic-3g8wm74b420bf334-1301145096.tcloudbaseapp.com/webclass/index.html#/
技术分享
1、前端技术导航大全 推荐:★★★★★
地址:前端技术导航大全
2、前端面试题库
推荐:★★★★★
地址:前端面试题库
3、开发者颜色值转换工具
推荐:★★★★★
地址 :开发者颜色值转换工具
2、前端边框阴影在线工具
推荐:★★★★★
地址:前端边框阴影在线工具
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构