JS防抖和节流
- 防抖:首先思考一个问题,防抖是如何产生的,抖动的现象又是什么,会造成什么样的影响,我们才能更好的理解防抖
先聊一下抖动的现象吧,假如现在有一个按钮,用户点一次,浏览器向服务器发起一次请求,返回一个值,!但是,这个用户手抖,喜欢在按钮上一直点,那么就会造成,浏览器一直向服务器发送请求,影造成服务器阻塞。这样明显不好。
所以就出现了防抖这个说法,就是为了控制用户点击时浏览器实际发送请求的次数。就是说,在1s内点击10次按钮,但这明显是用户手抖,才点了10次按钮,我们只需要发送1次请求就可以,因为这里的返回结果是一样的,假设设置时间间隔为1s,那么就是说在1s内发送10次请求,实际只发送1次请求,只有下一秒,再点击按钮,才会发送第二次请求,每次请求完毕之后都要清空定时器,才能执行下次用户点击事件。
下面用代码解释:
<body>
<div class="bg">
<button class="btn">剁手按钮</button>
</div>
</body>
首先在body里面定义了一个按钮,接着为按钮添加点击事件,这里用函数返回值,来替代请求服务器的返回结果,以下是JS代码:
<script>
//首先为button添加点击事件
const button = document.querySelector('button')
//定义函数ask
function payMoney() {
console.log('已剁'); console.log(this);
}
/* //定义一个防抖函数debounce,这里传入两个参数,
func为函数内部执行的函数,delay保存setTimeout的时间间隔*/
function debounce(func, delay) {
//定义变量timer为延时的名字,放在函数的外围,定义监听事件的同时定义了timer变量
//由于作用域链的关系,所有的独立的执行函数都能访问timer变量
let timer;
return function () {
//调整this的指向,让防抖函数this指向button
let context =this
let args =arguments
console.log(args);
//清除延时
clearTimeout(timer);
//在返回函数里面定义有个setTimeout,并且在setTimeout执行payMoney这个函数,
timer = setTimeout(function () {
//调整this的指向,让防抖函数this指向button
func.apply(context,arguments)
// console.log(context);
}, delay)
}
}
//在防抖函数执行的时候添加参数注明执行payMoney这个函数
button.addEventListener('click', debounce(payMoney, 1000))
</script>
这样我们就实现了,防抖功能的实现,可以有效解决在开发中遇到手抖的用户造成的问题了。
- 节流:防抖和节流一样,都是为了解决响应跟不上触发频率这类问题,如果我们需要统计用户滚动屏幕的行为来做出相应的网页行为,那么就需要进行节流操作了,如果用户不断滚动屏幕,就会不断产生请求,相应也在不断的增加,容易导致网络阻塞。我们就可以在触发事件的时候就马上执行任务,然后设定事件间隔限制,在这段时间内不管用户如何进行滚动都会忽视其操作,在时间到了以后,如何再检测到用户有滚动行为,再次执行任务,并且设置时间间隔。
2.大体流程如下:
触发事件 -> 执行任务 -> 设置时间间隔
如果时间间隔内有触发行为,就取消任务
如果时间间隔后有触发行为,就再次执行任务换人设置时间间隔
接下来用代码实现(JS代码):
/* 监听用户改变页面尺寸事件,并且在改变尺寸的时候相应的背景颜色改变 */
// 方法一:
//任务函数,为背景色设置随机值
function coloring (){
let r = Math.floor(Math.random() *255);
let g = Math.floor(Math.random() *255);
let b = Math.floor(Math.random() *255);
document.body.style.background = `rgb(${r},${g},${b})`;
}
//创建节流函数 参数:执行任务的函数func,延时的参数delay
function throttle(func,delay){
//变量time,通过闭包对变量进行操作
let time;
return function(){
//调整this的指向
let context = this
let args = arguments
//time为true则返回,不执行任务
if(time){
return;
}
//time没有被赋值,或者已经执行完毕了
time = setTimeout(function (){
//执行任务函数, 调整this的指向
func.apply(context,arguments)
time =null;
},delay)
}
}
//监听事件为resize,触发的任务函数为coloring,返回throttle,让对象执行coloring函数
window.addEventListener('resize',throttle(coloring,2000))
第二种方法:用Date(),获取当前时间节点与定义的时间节点做对比,也能实现同样的功能,JS代码如下:
function coloring (){
let r = Math.floor(Math.random() *255);
let g = Math.floor(Math.random() *255);
let b = Math.floor(Math.random() *255);
document.body.style.background = `rgb(${r},${g},${b})`;
}
function throttle(func,delay){
let pre = 0
return function(){
let now =new Date();
let context = this
let args =arguments
if(now -pre >delay){
func.apply(context,args)
pre = now
}
}
}
window.addEventListener('resize',throttle(coloring,2000))
OK,以上内容为个人对防抖和节流的理解,若有问题可以及时指出,定会改正.
PS:参考视频,技术蛋老师