什么是函数防抖?
在事件被触发n秒后再执行回调,如果在这n秒内又被触发, 则会重新计算函数延执行时间 。
比如:坐电梯的时候,如果电梯检测到有人进来(触发事件),就会多等待 10 秒,此时如果又有人进来(10秒之内重复触发事件),那么电梯就会再多等待 10 秒。
为什么需要函数防抖
-
onresize,scroll,mousemove ,mousehover 等,如果短时间内多次触发,不做限制的话,有可能一秒之内执行几十次、几百次,如果在这些函数内部执行了其他函数,尤其是执行了操作 DOM 的函数(浏览器操作 DOM 是很耗费性能的),那不仅会浪费计算机资源,还会降低程序运行速度,甚至造成浏览器卡死、崩溃。
-
短时间内重复的 ajax 调用不仅会造成数据关系的混乱,还会造成网络拥塞,增加服务器压力。
在实战中有过的应用场景
连续事件,只需触发一次回调的场景:
- 在做pc端自适应的时候,通过重写onresize事件、动态改变rem大小来实现的,可以用到防抖函数,等用户调整好页面再触发这个函数; 只需窗口调整完成后,计算窗口大小。防止重复渲染。
- 实现放大镜功能,用到了mousemove这个api实现放大功能;
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
实现防抖的思路
需要一个 setTimeout 来辅助实现,延迟运行需要执行的代码。
如果方法多次触发,则把上次记录的延迟执行代码用 clearTimeout 清掉,重新开始计时。
若计时期间事件没有被重新触发,等延迟时间计时完毕,则执行目标代码。
函数防抖的代码实现
并且为了方便防抖函数的调用和回调函数fn的传参问题,我们应该用闭包来解决这些问题。
function debounce(fn,wait){
var timer = null;
return function(){
var _this = this;
var args = arguments; // 取debounce执行作用域的this
if(timer !== null){
clearTimeout(timer);
}
timer = setTimeout(function(){
fn.apply(_this,agrs);// 用apply指向调用debounce的对象,相当于_this.fn(args);
},wait);
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("onresize",debounce(handle,1000));
什么是函数节流?
每隔一段时间,只执行一次函数
比如: 坐火车或地铁,过安检的时候,在一定时间(例如10秒)内,只允许一个乘客通过安检入口,以配合安检人员完成安检工作 ;
为什么需要函数节流?
和函数防抖的原因是一样的
函数节流实战场景
- 滚动加载,加载更多或滚到底部监听
- 高频点击提交,表单重复提交
函数节流实现思路
主要实现思路就是通过 setTimeout 定时器;或者通过实践戳来定;
- 时间戳: 通过比对上一次执行时间与本次执行时间的时间差与间隔时间的大小关系,来判断是否执行函数。若时间差大于间隔时间,则立刻执行一次函数。并更新上一次执行时间。
- 定时器:要注意的一点是:在delay后执行完fn之后清空timer,此时timer为假,throttle触发可以进入计时器
函数节流的代码实现
- 时间戳
function throttle(fn,wait){
var pre = Date.now();
// 使用闭包返回一个函数并且用到闭包函数外面的变量pre
return function(){
var _this = this;
var args = arguments;
var now = Date.now();
if(now-pre >= wait){
fn.apply(_this,args);
pre = now;
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
- 定时器
function throttle(fn,wait){
var timer;
return function(){
var _this = this;
var args = arguments;
//这时候如果timer存在,不给执行
if(timer){
return;
}
if(!timer){
timer = setTimeout(funciton(){
fn.apply(_this,args);
timer = null; // 在delay后执行完fn之后清空timer,此时timer为假,throttle触发可以进入计时器
},wait)
}
}
}
function handle(){
console.log(Math.random());
}
window.addEventListener("mousemove",throttle(handle,1000));
函数防抖和函数节流异同比较
-
相同点:
- 都可以通过setTimeout实现
- 目的都是降低回调执行频率。
-
不同点:
- 函数防抖关注一定时间连续触发的事件只在最后执行一次,而函数节流侧重于一段时间内只执行一次。