频繁触发回调导致的大量计算会引发页面的抖动甚至卡顿。为了规避这种情况,我们需要一些手段来控制事件被触发的频率。就是在这样的背景下,throttle(事件节流)和 debounce(事件防抖)出现了。
1.防抖
定义: 前面的所有触发都被取消,最后一次执行在规定的时间之后才会触发,也就是说如果连续快速的触发,只会执行一次。
常用场景:
- 搜索框搜索
- 在线文档保存
- 浏览器Scroll滚动
例子: 搜索框搜索内容
代码如下:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
</head>
<body>
<p>
请你输入搜索的内容: <input type="text"/>
</p>
<script>
let input = document.querySelector('input');
input.oninput = function(){
console.log('ajax 发请求..');
}
</script>
</body>
</html>
怎样实现防抖呢?
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
</head>
<body>
<p>请你输入搜索的内容: <input type="text" /></p>
<script>
// fn是我们需要包装的事件回调, interval是每次推迟执行的等待时间
function debounce(fn, interval = 300) {
// 定时器
let timer;
// 将debounce处理结果当作函数返回
return function () {
// 每次事件被触发时,都去清除之前的旧定时器
if (timer) {
clearTimeout(timer);
}
// 设立新定时器
timer = setTimeout(() => {
fn.apply(this, arguments);
}, interval);
};
}
let input = document.querySelector('input');
input.oninput = debounce(function () {
console.log('ajax 发请求..');
}, 1000);
</script>
</body>
</html>
防抖实现原理:
2.节流
定义: 在规定的间隔时间范围内不会重复触发回调,只有大于这个时间间隔才会触发回调,把频繁触发变为少量触发。
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
</head>
<body>
<div>
<h1>我是计数器<span>0</span></h1>
<button>点击我加上1</button>
</div>
<script>
let span = document.querySelector('span');
let button = document.querySelector('button');
let count = 0;
button.onclick = function () {
count++;
span.innerHTML = count;
console.log('执行');
};
</script>
</body>
</html>
上面的例子结果时: 没点击一次就会加1,无论速度多快,那么怎么实现在5秒内只能点击一次呢?
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
</head>
<body>
<div>
<h1>我是计数器<span>0</span></h1>
<button>点击我加上1</button>
</div>
<script>
// fn是我们需要包装的事件回调, delay是时间间隔的阈值
function throttle(fn, delay) {
// last为上一次触发回调的时间, timer是定时器
let last = 0,
timer = null;
// 将throttle处理结果当作函数返回
return function () {
// 保留调用时的this上下文
let context = this;
// 保留调用时传入的参数
let args = arguments;
// 记录本次触发回调的时间
let now = +new Date();
// 判断上次触发的时间和本次触发的时间差是否小于时间间隔的阈值
if (now - last < delay) {
// 如果时间间隔小于我们设定的时间间隔阈值,则为本次触发操作设立一个新的定时器
clearTimeout(timer);
timer = setTimeout(function () {
last = now;
fn.apply(context, args);
}, delay);
} else {
// 如果时间间隔超出了我们设定的时间间隔阈值,那就不等了,无论如何要反馈给用户一次响应
last = now;
fn.apply(context, args);
}
};
}
let span = document.querySelector('span');
let button = document.querySelector('button');
let count = 0;
button.onclick = throttle(function () {
count++;
span.innerHTML = count;
console.log('执行');
}, 5000);
</script>
</body>
</html>
3. 使用lodash 实现节流和防抖
官网: https://www.lodashjs.com/
通过npm 下载
npm i --save lodash
引入:
import _ from 'lodash';
使用
节流: _.throttle( fn, interval)
防抖: _.debounce(fn,interval)
上面例子重新用 lodash实现
1.节流
let span = document.querySelector('span');
let button = document.querySelector('button');
let count = 0;
button.onclick = _.throttle(function () {
count++;
span.innerHTML = count;
console.log('执行');
}, 5000);
````
**2.防抖**
````
import _ from 'lodash';
let input = document.querySelector('input');
input.oninput = _.debounce(function () {
console.log('ajax 发请求..');
}, 1000);
````