JS防抖和节流
什么是防抖和节流,作用是什么?
防抖: 通过setTimeout 的方式,在一定时间间隔内,将多次触发变成一次触发
节流: 减少一段时间的触发频率
一句话概括: 防抖是控制请求的次数,节流是控制请求的频率
作用: 前端性能优化利器,应用场景[按钮防重复提交,秒杀活动用户大量点击]
防抖的实现方式:
方式一:多次点击时最后一次的点击事件生效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,user-scalable=no">
<title>Document</title>
<style>
</style>
</head>
<body>
<button id="btn1">按钮1</button>
<script>
var btn1 = document.getElementById("btn1");
btn1.addEventListener('click', debounce1(submit, 1000), false);
//通过addEventListener绑定事件,该方法的第二个参数必须是一个函数,所以debounce1 必须返回的是一个函数,否则会立即执行
//方式一:多次点击时最后一次的点击事件生效
function debounce1(fn, timer) {
var t = null;
return function () {
if (t) {//如果t为true则先清除前一个定时器
clearTimeout(t);
}
t = setTimeout(() => {//在固定的时间内,只执行一次事件
fn.apply(this)
}, timer)
}
}
function submit() {
console.log(this);
}
</script>
</body>
</html>
方式二:多次点击时第一次点击生效,其余点击不生效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,user-scalable=no">
<title>Document</title>
<style>
</style>
</head>
<body>
<button id="btn2">按钮2</button>
<script>
var btn2 = document.getElementById("btn2");
btn2.addEventListener('click', debounce2(submit, 1000), false);
//通过addEventListener绑定事件,该方法的第二个参数必须是一个函数,所以debounce2 必须返回的是一个函数,否则会立即执行
//方式二:多次点击时第一次点击生效,其余点击不生效
function debounce2(fn, timer) { //debounce
var t = null;
return function () {
var firstClick = !t;
if (t) { //如果已经存在了定时器则将定时器先清除
clearTimeout(t);
}
if (firstClick) {//t为null,!t则为true,firstClick为true,执行事件
fn.apply(this)
}
t = setTimeout(() => {
t = null;//开启了一个定时器,在固定的时间内,t有值,则!t为false,firstClick为false,不执行事件
}, timer)
}
}
function submit() {
console.log(this);
}
</script>
</body>
</html>
节流的实现方式:
方式一: 通过时间戳计算请求事件间隔,时间间隔大于限制时间则执行,否则不执行
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,user-scalable=no">
<title>Document</title>
<style>
</style>
</head>
<body>
<button id="btn1">按钮1</button>
<script>
var btn1 = document.getElementById("btn1");
btn1.addEventListener('click', throttle(submit, 2000), false);
function throttle(fn, delay) {
var begin = 0;
return function () {
var cur = new Date().getTime()//获取当前时间
if (cur - begin >= delay) {//当前时间如果大于或等于间隔时间,则执行一次事件请求
console.log(cur - begin);
begin = cur;
fn.apply(this)
}
}
}
function submit() {
console.log(this);
}
</script>
</body>
</html>
方式二:通过setTimeout,定时器不为空则不执行,为空则重新启动一个定时器执行事件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0,user-scalable=no">
<title>Document</title>
<style>
</style>
</head>
<body>
<button id="btn1">按钮1</button>
<script>
var btn1 = document.getElementById("btn1");
btn1.addEventListener('click', throttle(submit, 2000), false);
var t = null;
function throttle(fn, timer) {
return function () {
if (!t) {
t = setTimeout(() => {
t = null;
fn.apply(this)
}, timer)
}
}
}
function submit() {
console.log(this);
}
</script>
</body>
</html>