前言
各位掘友们平时都没少上网噜,在冲浪的时候没少遇到过网络卡顿的情况,每当点击链接或者图片没有反应的时候,就会烦躁地一通乱点,那么掘友们有没有想过在你的一番操作之下,这个程序究竟在背地里运行了多少次?一次?好多次?好好好,今天我们就要来聊聊点点点的那些事。
防抖
掘友们从名字就能看出点门道来。防抖------就是防止 '帕金森' 网友的手抖。防抖是指在一定时间内,如果事件被频繁触发,只执行最后一次事件。可以用于优化一些高频率触发的事件,比如窗口大小改变,滚动事件等。也就是说当网友点击一个提交按钮后1s后进行提交,但是网友在1s内重复点击,那么就从最后一次点击开始计算1s后进行提交。
那么我们要如何实现这个效果呢?我们一起来看看:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">提交</button>
<script>
function send(e){
console.log(this,'提交完成',e);
}
let btn = document.getElementById('btn')
btn.addEventListener('click',debounce(send,1000))
function debounce(fn,delay){
let timer;
return function(){
let args = arguments
if(timer) clearTimeout(timer)
timer= setTimeout(() => {
fn.call(this,...args)
},delay)
}
}
</script>
</body>
</html>
首先我们设置了一个button用来模拟点击提交事件。接下来,为了监听按钮我们得在按钮上设置一个监听器。点击按钮以后,我们就运行debounce()
js
function debounce(fn,delay){
let timer;
return function(){
let args = arguments
if(timer) clearTimeout(timer)
timer= setTimeout(() => {
fn.call(this,...args)
},delay)
}
}
在debounce()
中传入了两个参数,fn 和 delay ,fn 是一个函数,也就是我们要进行的各种操作,也就是点击按钮后的一些操作,delay 就是我们设置的延迟时间。在函数体内,我们先声明了一个timer ,用来记录我们的计时器,如果在之前点击了按钮,那么timer 就不为空,当再次点击按钮时,判断timer 不为空,于是调用clearTimeout()
方法,将定时器重置,实现在一定时间内只执行最后一次操作的效果。
细心的掘友会发现,如果我的send()
方法中传入多个参数,那么怎么办呢?我们可以看到,在函数体内调用fn()
方法的时候使用了解构,让fn()
传入的实参解构再调用,那么无论fn()
中有多少个形参,都能使用防抖。(不了解解构的掘友们请移步"跃迁ES6:探索JavaScript语言的最新进展(一)")
在这个防抖函数的实现中,fn
函数是通过 call()
方法调用的。具体来说,fn.call(this, ...args)
的作用是:将 fn
函数中的 this
指向当前上下文中的 this
(也就是防抖函数返回的新函数的执行环境),并将传入的 args
参数展开后作为参数传递给 fn
函数。
节流
好好好,刚才我们从防抖的名字就能看出点门道来,那么这节流又是一个啥玩意?节流(throttle)指的是在一定时间间隔内只执行一次函数,用于优化高频率触发的事件,比如 scroll
、resize
和 mousemove
等。与防抖不同的是,节流函数会按照固定的时间间隔执行函数,而不是在等待一段时间后才执行。
我们话不多说,先上代码:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id = "btn">提交</button>
</body>
<script>
function send(){
console.log('提交完成');
}
let btn = document.getElementById('btn')
btn.addEventListener('click',throttle(send,1000))
function throttle(fn,delay){
let prevTime = Date.now()
return function(){
if(Date.now()-prevTime>delay){
fn.apply(this,arguments)
prevTime = Date.now()
}
}
}
</script>
</html>
同样的我们看到throttle()
方法
js
function throttle(fn,delay){
let prevTime = Date.now()
return function(){
if(Date.now()-prevTime>delay){
fn.apply(this,arguments)
prevTime = Date.now()
}
}
}
与防抖方法不一样的地方是,不管我们在delay 这段时间内点击了多少次,我们只在 delay 时间过去后调用一次fn 方法。那么我们是如何记录时间的呢?这里使用到了Date.now()
,这个方法返回的是现在距离1970年经过的毫秒数,储存在prevTime 变量中,如果后面的点击时间距离第一次点击时间大于delay 则运行 fn ,掘友们要注意的是,在运行以后,要将prevTime的时间进行更新,这样才能保证下一次点击事件的正确运行。
结尾
在实际开发中,合理地运用节流和防抖可以减少不必要的函数执行,降低资源消耗,提升页面响应速度。无论是处理 DOM 事件、AJAX 请求还是其他异步操作,都可以考虑使用节流和防抖来优化程序性能。希望本文对你有所帮助,也欢迎读者在实际项目中尝试运用这两种技巧,从而改善用户体验,提升应用性能。"