分为文字版和思维导图版(在文末)
一、防抖
1.含义
当事件被触发n秒后再执行回调,如果在n秒内又被触发,则重新计时。
2.使用场景
- 搜索输入框的联想功能,当不再输入后的几百毫秒再去发送请求,减少服务器压力。
- 不停改变浏览器窗口大小resize,引起浏览器的重排,消耗性能
3.函数实现
function debounce(func, delay) {
let timer;
return function () {
let context = this;
let args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function () {
func.apply(context, args);
// 其实就是 context.func(args)
}, delay);
};
}
二、节流
1.含义
规定在一个单位时间内只能触发一次函数,若在单位时间内多次触发,则只执行1次。
2.使用场景
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
3.函数实现
(1)时间戳
function throttle(fn, wait) {
var args;
// 前一次执行的时间戳
var previous = 0;
return function() {
// 将时间转为时间戳
var now = +new Date();
args = arguments;
// 时间间隔大于延迟时间才执行
if (now - previous > wait) {
fn.apply(this, args);
previous = now;
}
};
}
(2)定时器
function throttle(fn, wait) {
var timer, context, args;
return function() {
context = this;
args = arguments;
// 如果定时器存在,则不执行
if (!timer) {
timer = setTimeout(function() {
// 执行后释放定时器变量
timer = null;
fn.apply(context, args);
}, wait);
}
};
}
4.拓展
函数实现:不希望非要等到事件停止触发后才执行,我希望立刻执行函数,然后等到停止触发 n 秒后,才可以重新触发执行
function debounce(func, wait, immediate) {
var timeout, result;
return function () {
var context = this;
var args = arguments;
if (timeout) {
clearTimeout(timeout);
}
if (immediate) {
// 如果已经执行过,不再执行
var callNow = !timeout;
timeout = setTimeout(function(){
timeout = null;
}, wait)
if (callNow) {
result = func.apply(context, args)
}
}
else {
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
return result;
}
}
三、对比
1.相同
- 本质目的是为了节省程序的性能(防止高频函数调用)
- 都借助了闭包的特性来缓存变量(状态)
- 都可以使用setTimeout实现
2.不同
侧重点不同:防抖侧重于稳定只能执行一次,而节流强调限周期内次数,即执行频率,不限制所有时间内的总次数
四、lodash
lodash中文文档
https://www.lodashjs.com/docs/lodash.debounce
https://www.lodashjs.com/docs/lodash.throttle
思维导图
参考文章链接
https://juejin.cn/post/6893748375372431368#heading-1
https://juejin.cn/post/6844903752063778830#heading-2
https://juejin.cn/post/6844903795420299278