本质都是为了防止函数高频调用,利用闭包特性来缓存变量(状态)。
1、防抖(debounce)重在清零 clearTimeout(timer),执行最后一次
原理:调用函数fn在一段时间后才执行,如果这段时间再次调用,则重新计算执行时间,如果规定的时间没有再次调用该函数,则执行函数fn
function debounce(fn, wait) {
let timer = null;
return function () {
let _this = this;
let _arg = arguments;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(function () {
fn.apply(_this, _arg);
}, wait);
}
}
如果需要第一次立即执行,可以加个immediate参数,表示是否立即执行,函数里加个count计数,如果是第一次并且immediate 为ture时立即执行。
function debounce(fn, wait, immediate) {
immediate = immediate || false;
let timer = null;
let count = 0;
return function () {
let _this = this;
let _arg = arguments;
clearTimeout(timer);
if (immediate && !count) {
fn.apply(_this, _arg);
count++;
} else {
timer = setTimeout(function () {
fn.apply(_this, _arg);
count++;
}, wait);
}
}
}
需要注意的点就是this指向问题和函数参数如何获取
应用场景:1、按钮提交事件 2、scroll事件滚动触发 3、表单元素实时校验 4、用户编辑实时保存 5.调整浏览器窗口resize
2、节流(throttle)重在 开锁关锁 timer=timeout; timer=null,间隔执行
原理: 单位时间内,只能触发一次fn函数。如果这个单位时间内触发多次函数,只有一次生效。
1、通过定时器实现。只会在time时间内触发一次。
function throttle(fn, time) {
let timer = null;
return function() {
let _this = this;
let args = arguments;
if(!timer) {
timer = setTimeout(() => {
timer = null;
fn.call(_this, args);
}, time)
}
}
}
2、通过时间戳实现。可以在立即执行一次,之后在time时间内只触发一次fn函数。
function throttle(fn, time) {
let initialTime = 0;
return function() {
let _this = this;
let args = arguments;
let currrentTime = new Date().getTime();
if(currrentTime - initialTime > time){
initialTime = currrentTime;
fn.apply(_this, args);
}
}
}
应用场景:1、input实时搜索请求接口 2、dom元素拖拽 3、射击游戏(鼠标) 4、计算鼠标移动距离 5、监听滚动条事件,是否滑动到底部加载更多 6、跟随鼠标一些动画