前言
防抖节流都是属于前段性能优化内容
我的理解是在进行一次指定的事件操作后在延迟指定的delay时间段内没有再一次发生对应的事件那么在延迟时间结束后,就会执行一次指定的处理函数,而相对应的在指定延迟时间段内你又一次触发了相应的事件那么debouce会再一次延迟你指定的延迟时间,
应用场景:
1.登录按钮(我希望在一定时间里我只向服务器端提交一次数据,从而避免了在网络缓慢的时候用户没能在很短的时间里得到相应而在短时间里进行多次提交操作)
2.搜索框
3.鼠标onmousemove事件等
本文以鼠标onmousemove事件为例代码如下
let app = document.getElementById('app')
app.onmousemove = function(e){
var e = e || window.event
console.log(e.clientX)
}
如图所示,当你在app上移动鼠标的时候及时只是一点点移动也会触发一连串的事件,在实际开发中如果事件处理函数足够庞大,会大大影响页面的额性能
<body>
<div id="app"></div>
</body>
<script>
//防抖
let app = document.getElementById('app')
app.onmousemove = debounce(move,1000)
function debounce(func, delay){
var timer=null;
return function (){
timer&&clearTimeout(timer);
// console.log(this)
timer = setTimeout(()=>{
func.apply(this, arguments)
},delay)
}
}
function move(e){
console.log(e.clientX)
console.log(this,arguments)
}
上诉的debounce函数利用了闭包的原理,每次执行操作函数时都会先对timer就行判断通过clearTimerout对其清除然后从新创建timer,我这里将具体的处理函数move()提取到外面方便以后管理和扩展,通过apply来传递this,
和 arguments,以便在move()中对事件对象和dom对象的使用
在move中打印this和 arguments
div是操作的dom对象,arguments 则包含了事件对象
-封装节流函数分析:当触发事件时,每指定时间触发一次事件处理函数。
1.当用户持续触发这个函数时,即前后两次触发间隔小于指定时间,函数不会立即触发函数,会在指定时间后触发函数,简而言之就是可以连续触发事件,但是在一定的时间里只执行一次函数
下面这段代码是节流函数的简单实现
let app = document.querySelector('#app')
console.log(app)
app.onmousemove = jl(move, 400)
function jl(func, await) {
var timer = null;
return function() {
var args = arguments;
console.log(timer)
if (!timer) {
timer = setTimeout(() => {
clearTimeout(timer)
func.apply(this, arguments)
}, await)
}
}
}
function move(e) {
console.log(this, arguments)
this.innerHTML = e.clientX
}
可是上面代码有一个小问题
他仅仅自会执行一次通过打印timer 可以看到输出的是1,这导致if条件不满足,
if (!timer) {
console.log(timer) ---输出null
timer = setTimeout(() => {
console.log(timer) ---输出1
console.log('setTimerout')
clearTimeout(timer)
func.apply(this, arguments)
}, await)
console.log(timer) --输出 1
}
通过测试第一次执行的时候 在 setTimeout()内部timer 是有值的 但是却没有能够通过clearTimeout(timer)进行清除 这是我没看懂的地方 ,寻思了很久也没想明白 ,如果有知道的 麻烦通知小弟一声
不过却又解决办法
。
function jl(func, await) {
var timer = null;
return function() {
var args = arguments;
// console.log(timer)
if (!timer) {
timer = setTimeout(() => {
timer = null
func.apply(this, arguments)
}, await)
}
}
}
下面是一种利用时间戳的方法实现
```javascript
```javascript
function jl(func, await) {
var last = 0;
return function() {
var args = arguments;
var now = new Date().getTime()
if (now - last > await) {
func.apply(this, args)
last = now
}
}
}
通过时间戳 判断 两次间隔时间大于await 的时候就执行函数 func ,同时更新last