今天我们的目标是能够手写防抖&节流函数
防抖
概念:触发事件后在 n 秒内函数只能执行一次 如果在 n 秒内又触发了事件 则重新计算函数执行时间
我们什么时候需要防抖函数来优化呢? 高频触发的事件,比如我们会狂点按钮,疯狂移动等
// 需要防抖处理
let box = document.querySelector('.box')
box.onmousemove = function(e){
box.innerHTML = e.clientX
}
我们先来实现一个简版的防抖函数来处理
// 简单版防抖函数
// 出现的问题 上来第一次不执行
let box = document.querySelector('.box')
let boxDebounce = debounce(move,1000)
box.onmousemove = boxDebounce
function move(e){
box.innerHTML = e.clientX
}
function debounce(fn,wait){
let timer = null
return function(){
let args = arguments
timer && clearTimeout(timer)
timer = setTimeout(()=>{
fn.apply(this,args)
},wait)
}
}
简单版防抖函数 我们实现了,但是第一次上来根本没有立刻执行,做一下升级
// 升级版防抖函数 上来第一次执行
let box = document.querySelector('.box')
let boxDebounce = debounce(move,1000)
box.onmousemove = boxDebounce
function move(e){
box.innerHTML = e.clientX
}
function debounce(fn,wait){
let timer = null
return function(){
let args = arguments
let now = !timer;
timer && clearTimeout(timer)
timer = setTimeout(()=>{
timer = null
},wait)
// if(now){
// fn.apply(this,args)
// }
now ? fn.apply(this,args)
: ''
}
}
自己在设计防抖函数的时候也可以自己在设置一个额外的参数来取代这里的变量now哈
节流
概念:连续触发的事件我们使其一定时间内触发一次
同样用这个box举例
let box = document.querySelector('.box')
let boxReduce = reduce(move,400)
box.onmousemove = boxReduce
function move(e){
box.innerHTML = e.clientX
}
function reduce(fn,wait){
let timer = null
return function(){
let args = arguments
if(!timer){
timer = setTimeout(()=>{
timer = null
fn.apply(this,args)
},wait)
}
}
}
我们在这里只是将timer设置为null,但是并没有清除定时器,看似没什么影响,我们也应该解决的更细致一些,优化它(使用时间戳去替换timer,不用setTimeout)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
background: #00acec;
height: 500px;
}
</style>
</head>
<body>
<div class="box"></div>
<script>
let box = document.querySelector('.box')
let boxReduce = reduce(move,400)
box.onmousemove = boxReduce
function move(e){
box.innerHTML = e.clientX
}
// function reduce(fn,wait){
// let timer = null
// return function(){
// let args = arguments
// if(!timer){
// timer = setTimeout(()=>{
// timer = null
// fn.apply(this,args)
// },wait)
// }
// }
// }
function reduce(fn,wait){
let last = 0
return function(){
let args = arguments
let now = Date.now()
if(now - last > wait){
fn.apply(this,args)
last = now
}
}
}
</script>
</body>
</html>