一.debounce函数原理
1.简单写如下
function debounce() {
let t = null
if(t !== null){
clearInterval(t)
}
t = setTimeout(()=>{
console.log('zzz')
},500)
}
这样写业务逻辑和防抖函数混合在了一起,不是很好
2.改进如下
debounce(function (){
console.log('zzz')
},delay)
function debounce(fn,delay){
let t = null
return function(){
if(t !== null){
clearInterval(t)
}
t = setTimeout(()=>{
fn.call(this)
},delay)
}
}
那我们封装防抖函数的思路是什么呢?就是利用异步来进行,将本该进行的操作延后,以下面程序为例
程序开始运行的时候,将业务逻辑代码放入定时器,定时器放入异步调用队列,所以第一次执行完以后,异步调用队列里面有一次定时器操作,此时如果再次进行操作的话,那么第二次t不为空,刚好被clearTimeout清除,所以怎么被延迟的呢,就是我上一步加入了异步队列,然后下一步执行的时候,你把我给干掉了,然后将第二次的定时器加入了异步队列。直到你不再调用防抖函数
3.下面我们进行更加完善的封装
function debounce(fn,delay){
let t = null
const _debounce = function(...args){
if(t){
clearTimeout(t)
}
t = setTimeout(()=>{
fn.apply(this,args)
})
}
return _debounce
}
3.1.立即执行功能
刚开始输入的时候,就发送一次请求,然后开始延迟调用利用一个第三方变量来控制,最好不要随意改变输入的参数的内容,刚开始的时候定义isInvoke 这个变量用来动态控制第一次输入立即执行,immediate控制是否立即执行,false就是不允许,true就是允许,把它当做参数传递进去,而不是随意改变它的值,我们来走一遍程序:当immediate为true 的时候,立即执行一次函数,然后将isInvoke改变为true,这样一来就下一次就不能立即执行了,除非改变为false,那么此时此刻程序就又是普通的防抖函数,
function debounce(fn,delay,immediate){
let t = null
let isInoke = false
const _debounce = function(...args){
if(t){
clearTimeout(t)
}
if(immediate && !isInvoke){
fn.apply(this,args)
isInvoke = true
}else{
t = setTimeout(()=>{
fn.apply(this,args)
isInoke = false
})
}
}
}
3.2.取消功能
点击按钮取消可以取消发送请求,在定时器期间用户想要取消这个输入内容 ,当我们不调用防抖函数的时候,此时,就开始调用异步队列里面的定时器,那么在定时器结束之前的期间我们可以进行将定时器删除,这样就不会执行业务逻辑了,也就不会发送请求了
function debounce(fn,delay,immediate){
let t = null
let isInoke = false
const _debounce = function(...args){
if(t){
clearTimeout(t)
}
if(immediate && !isInvoke){
fn.apply(this,args)
isInvoke = true
}else{
t = setTimeout(()=>{
fn.apply(this,args)
isInoke = false
})
}
}
_debounce.cancel = function(){
if(t){
clearTimeout(t)
}
t = null
isInvoke = false
}
return _debounce
}
3.3.防抖函数的返回值 可以利用promise返回
function debounce(fn,delay,immediate){
let t = null
let isInoke = false
const _debounce = function(...args){
return new Promise((resolve,reject)=>{
if(t){
clearTimeout(t)
}
if(immediate && !isInvoke){
fn.apply(this,args)
isInvoke = true
}else{
t = setTimeout(()=>{
fn.apply(this,args)
isInoke = false
})
}
})
}
_debounce.cancel = function(){
if(t){
clearTimeout(t)
}
t = null
isInvoke = false
}
return _debounce
}
<script>
var inp = document.querySelector('input')
//
let count = 0
let fn = function() {
console.log(`发送了${++count}次请求`, this, event);
return 'zhaobo'
}
// const debounceChange = debounce(fn, 500, true, (res) => {
// console.log(res);
// })
// inp.oninput = debounceChange
const debounceChange = debounce(fn, 500, true, (res) => {
console.log(res);
})
const tempClick = () => {
debounceChange().then(res => {
console.log('promise返回值', res);
})
}
inp.oninput = tempClick
let cancelBtn = document.querySelector('#cancel')
cancelBtn.onclick = function() {
debounceChange.cancel()
}
// let cancelBtn = document.querySelector('#cancel')
// cancelBtn.onclick = function() {
// debounce.cancel()
// }
</script>
\