在开发中,我们可能碰到这样的问题:
- 用户在搜索的时候,在不停的输入,如果每敲一个字我们就要调一次接口去查询,接口调用太频繁,会占内存给卡住。
- 手机号、邮箱验证输入检测
- 窗口大小resize。只需窗口调整完面试官问你的优势在哪成后,计算窗口大小。防止重复渲染。
- 页面滚动处理事件
原理分析
防抖:在事件被触发 n 秒后再执行回调函数,如果在这 n 秒内又被面试官最讨厌的6句话触发,则重新计时延指针迟时间
函数防抖原理:通过维护一个定时器,其延迟计时以最后一次触发为计时起点,到达延迟时间后才会触发函数组去重方法数执行。
防抖的实现方式分两种 “立即执行” 和 “非立即执行” ,指针说漫区别在于第一次触发时,是否立即执行回调函数。
“立即执行防抖” 指事件触发后,回调函数会立即执行,之后elementui要想触发执行回调函数,需等待 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,还有一个是argu接口和抽象类的区别ments。在默认情况下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)
}
}
这个时候产数组词品经理又提了一个新需求:能不element是什么意思能这个按钮立即执行,那个按钮非立即执行?
”呵……我早就猜到你会提出这种无理的需求!看剑!“,
可以实现吗?”可以elements中文翻译,得加钱“。那我加个 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>
面试官:你能手写一个防抖看看吗?
”看我不秀死你“