5 节流和防抖概念,手写,区别
5 节流和防抖
参考多个博客写的,如果有侵权,请联系我
https://www.jianshu.com/p/c8b86b09daf0
5.1 防抖
1 防抖的概念
https://github.com/mqyqingfeng/Blog/issues/22
https://www.jianshu.com/p/c8b86b09daf0
防抖是防止事件多次调用。假设一个用户频繁触发某个事件,且每次触发事件的间隔小于wait,防抖的情况下只会调用一次。 (多次触发转化为一次触发)
2 手写防抖函数
1 非立即执行版和立即执行版
防抖函数分为非立即执行版和立即执行版。
非立即执行版:等到事件停止触发后才执行
立即执行版:立刻执行函数,然后等到停止触发wait时间后,才可以重新触发执行。
2 func.apply(context, args)函数
绑定this的作用:context(this)参数,保证使用防抖函数前后this指向一致
确定arguments(args)的作用:保证使用防抖函数前后event事件对象指向一致
<body>
<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
let num = 1;
let content = document.getElementById('content');
function count(e) {
content.innerHTML = num++;
console.log(this);
console.log(e);
}
function debounce(func, wait, immediate) {
//声明计时器,必须在return外面,表示闭包,这个会一直存在于内存,对于每一个return返回的函数都是共用该变量
let timeout = null; //声明计时器。nodejs里面setTimeout()返回的是一个Timeout类,而不是一个整数的id;谷歌浏览器返回的是一个整数,表示id
return function (){
let context = this;//获取调用(return返回的)函数的对象(执行上下文)。通俗说那个对象调用函数func
let args = arguments;//获得参数,保证count中的event事件对象和原来一样
if(timeout){ //可以不判断就清除定时器
clearTimeout(timeout);//注意取消定时器,只是取消执行定时器中的回调函数。timeout的值不会变,不会变
}
if (immediate) { //立即执行
//callNow刚刚开始为true,在有了定时器之后,便一直未false,直到执行定时器中的回调才会改变
var callNow = !timeout; //注意这里使用var,不然会报错,计时器的返回值为全局变量(????好像let也行)
timeout = setTimeout(() => {
timeout = null;
}, wait);
if (callNow) {//
func.apply(context, args);
/*func(); //如果这里不使用apply方法改变this指向,那么count中的this指向Window,没有指定参数args,那么e指向undefined。与没有使用防抖前不一样*/
}
}
else { //非立即执行
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
}
content.onmousemove = debounce(count, 1000, true);
//content.onmousemove = count; //没有防抖时,count中this指向id="content"的这个元素,e指向MouseEvent事件
</script>
</body>
5.2 节流
1 定义
https://github.com/mqyqingfeng/Blog/issues/26
所谓节流,如果你持续触发事件,每隔一段时间(wait),只执行一次事件。节流会稀释函数的执行频率。
2 两种实现方式
1 节流一般有两种方式可以实现,分别是时间戳版和定时器版。
1)时间戳版:立刻执行,事件停止触发后没有办法再执行事件
使用时间戳,当触发事件的时候,我们取出当前的时间戳,然后减去之前的时间戳(最一开始值设为 0 ),如果大于设置的时间周期,就执行函数,然后更新时间戳为当前的时间戳,如果小于,就不执行。
2)定时器版:事件会在 n 秒后第一次执行,事件停止触发后依然会再执行一次事件
当触发事件的时候,我们设置一个定时器,再触发事件的时候,如果定时器存在,就不执行,直到定时器执行,然后执行函数,清空定时器,这样就可以设置下个定时器
3)两者区别。假如持续移动鼠标时间是4.2秒,节流设置时间为1秒;
时间戳版:当鼠标移入的时候,事件立刻执行,每过 1s 会执行一次,如果在 4.2s 停止触发,以后不会再执行事件。
定时器:当鼠标移入的时候,事件不会立刻执行,晃了 1s 后终于执行了一次,此后每 1s 执行一次,当数字显示为 4的时候,立刻移出鼠标,相当于大约 4.2s 的时候停止触发,但是依然会在第5s 的时候执行一次事件
3 代码
1)时间戳版
<body>
<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
let num = 1;
let content = document.getElementById('content');
function count() {
content.innerHTML = num++;
}
/**
* @desc 函数节流
* @param func 回调函数
* @param wait 延迟执行毫秒数
*/
function throttle(func, wait) {
//闭包
let previous = 0; //保存上一次调用回调函数的时间,初始为0,表示立即触发(因为当前时间搓很大,相减肯定大于wait)
return () => {
let now = +Date.now(); //返回自1970年1月1日00:00:00 UTC以来经过的毫秒数。
let ctx = this;
let args = arguments; //时间戳版,可以不需要写这个,后面直接使用arguments。但是为了避免出错也可以写上
if(now - previous > wait){
func.apply(ctx, args);
previous = now;
}
}
}
content.onmousemove = throttle(count, 1000); //这里的throttle只会执行一次,返回的函数才是回调函数,会多次触发
</script>
</body>
2)定时器版
<body>
<div id="content" style="height:150px;line-height:150px;text-align:center; color: #fff;background-color:#ccc;font-size:80px;"></div>
<script>
let num = 1;
let content = document.getElementById('content');
function count() {
content.innerHTML = num++;
}
/**
* @desc 函数节流
* @param func 回调函数
* @param wait 延迟执行毫秒数
*/
function throttle(func, wait) {
//闭包
let timeOut = null; //声明定时器
return () => {
let ctx = this;
let args = arguments;
if(!timeOut){ //定时器不存在时,才会执行
timeOut = setTimeout(() => {
func.apply(ctx, args);
timeOut = null; //执行一次之后,重新赋值,表示定时器不存在。
//clearTimeout(timeOut) //不能使用这个清除,因为清除定时器,但是timeOut值还是不变,不是null
}, wait);
}
}
}
content.onmousemove = throttle(count, 1000); //这里的throttle只会执行一次,返回的函数才是回调函数,会多次触发
</script>
</body>
5.3 防抖和节流解决的问题
在前端开发的过程中,我们经常会需要绑定一些持续触发的事件,如 resize、scroll、mousemove 等等,但有些时候我们并不希望在事件持续触发的过程中那么频繁地去执行函数。
节流:一般是onrize,onscroll等这些频繁触发的函数,比如你想获取滚动条的位置,然后执行下一步动作;鼠标不断点击触发,mousedown(单位时间内只触发一次)
防抖:频繁操作点赞和取消点赞,因此需要获取最后一次操作结果并发送给服务器;search搜索一个词时,用户在不断输入值时…
5.4 区别
防抖和节流的作用都是防止函数多次调用。区别在于,假设一个用户一直频繁触发这个函数,且每次触发函数的间隔小于wait,防抖的情况下只会调用一次,而节流的情况会每隔一定时间(参数wait)调用函数。
5.5 小结
百里于2020年7月15日
如果有错,请您指出!如有侵权,请联系我删除!
本文地址:https://blog.csdn.net/abc1194474469/article/details/107359154