防抖
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
解决方法:每次触发事件时都取消之前的延时调用方法
应用场景:实现一个搜索功能,input需要绑定onchange事件,在onchange事件里调后台接口,此时,输入一个字母就进行一次请求,连续输入就会进行很多次请求,性能不太好,这时候就需要加一个防抖,如果连续输入,就等最后一个字母输入几秒之后再调接口。
实现思路:通过闭包维护一个变量,此变量代表是否已经开始计时,如果已经开始计时则清空之前计时器,重新计时。
实现方法:
//防抖debounce代码:
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
// 每当用户输入的时候把前一个 setTimeout clear 掉
clearTimeout(timeout);
// 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, 500);
};
}
// 处理函数
function handle() {
console.log(Math.random());
}
// 滚动事件
window.addEventListener('scroll', debounce(handle));
下面是我自己写的小例子
!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>防抖</title></head>
<body>
<input type="text" class="form-control" placeholder="请输入搜索关键字" id="search">
</body>
<script>
var input = document.getElementById("search") // 防抖debounce代码:
function debounce(fn) {
let timeout = null; // 创建一个标记用来存放定时器的返回值
return function () {
// 每当用户输入的时候把前一个 setTimeout clear 掉
clearTimeout(timeout); // 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.apply(this, arguments);
}, 600);
};
}
// 处理函数
function handle() {
console.log("我进行请求了");
}
//input.oninput = debounce(handle)
input.addEventListener('input', debounce(handle));
</script>
</html>
节流
高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
解决方法:每次触发事件时都判断当前是否有等待执行的延时函数
应用场景:连续点击事件或者鼠标移动事件。里面要调接口的话,也会连续调无数次,此时加个节流,让该事件再n秒之内只执行一次。提高了性能。
实现思路:通过闭包维护一个变量,次变量代表是否允许执行函数,如果允许则执行函数并且把该变量修改为不允许,并使用定时器在规定时间后恢复变量。
实现方法:
<script>
//节流throttle代码:
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () {
// 在函数开头判断标记是否为true,不为true则return
if (!canRun) return;
// 立即设置为false
canRun = false;
// 将外部传入的函数的执行放在setTimeout中
setTimeout(() => {
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
// 当定时器没有执行的时候标记永远是false,在开头被return掉
fn.apply(this, arguments);
canRun = true;
}, 500);
};
}
function sayHi(e) {
console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListener('resize', throttle(sayHi));
</script>
下面是我自己写的小例子:
<!DOCTYPE html>
<html lang="en"><head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>节流</title>
</head>
<body>
<div id="btn">点我抢购</div>
</body>
<script>
var btn = document.getElementById("btn"); //节流throttle代码:
function throttle(fn) {
let canRun = true; // 通过闭包保存一个标记
return function () { // 在函数开头判断标记是否为true,不为true则return
if (!canRun) return; // 立即设置为false
canRun = false; // 将外部传入的函数的执行放在setTimeout中
setTimeout(() => {
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
// 当定时器没有执行的时候标记永远是false,在开头被return掉
fn.apply(this, arguments);
canRun = true;
}, 1000);
};
}
function sayHi(e) {
console.log("我抢到了,哈哈哈");
}
btn.addEventListener('click', throttle(sayHi));
</script>
</html>