防抖 和 节流 是 闭包的实际应用
防抖
- 高频的触发事件,规定时间内触发会被清除,只有当超过规定时间触发,然后执行最后一次事件
节流
- 高频的触发事件,限制触发次数,规定时间内只能触发一次
防抖实现
案例:输入框联想
<input type="text">
未使用防抖
let ipt = document.querySelector('input');
ipt.oninput = function() {
console.log(this.value + ' 发送请求');
}
效果图
随便几个字就要发送几十条请求。服务器:不带这么折腾 “人” 的
使用了防抖
let ipt = document.querySelector('input');
ipt.oninput = debounce(showValue, 500);
function debounce(fn, delay) {
let timer = null;
return function () { // 函数内部能访问外面的 变量timer,所以是一个 闭包
if(timer) {
// timer 有值说明有任务正在运行,清除掉执行新的任务
clearTimeout(timer);
}
timer = setTimeout(() => {
// 调用 fn 回调函数,使用 call 改变函数 this 的指向,这里的 this 指向的是 ipt 输入框,所以可以直接call this
fn.call(this);
// delay 定义超过多少时间不调用才执行事件
}, delay)
}
}
function showValue() {
// 因为使用 call 把 this指向了 ipt,所以这里可以直接使用 this,不然的话指向的是 window对象
console.log(this.value);
}
效果图
只发送一条请求。服务器:“舒服”
节流实现
案例:屏幕滚动背景变色
body {
height: 2000px;
}
未使用节流
window.onscroll = changColor;
function changColor() {
let r = Math.floor(Math.random() * 255);
let g = Math.floor(Math.random() * 255);
let b = Math.floor(Math.random() * 255);
document.body.style.background = `rgb(${r}, ${g}, ${b})`
}
效果图
这频率不得闪瞎用户高贵的 () 眼?
使用了节流
方式一:定时器
window.onscroll = throttle(changColor, 1000);
// 定时器
function throttle(fn, delay) {
let flag = true;
return () => {
if (flag) {
setTimeout(() => {
fn();
// 执行完逻辑把 flag 还原为 true,下次就可以再次执行了
flag = true;
}, delay)
}
// 定时器里面的函数没执行完成,flag 一直为 false,一直不会再次执行定时器里面的代码,只有等到函数事件执行完成之后,把 flag 设置为 true才可以执行下一次事件
flag = false;
}
}
function changColor() {
let r = Math.floor(Math.random() * 255);
let g = Math.floor(Math.random() * 255);
let b = Math.floor(Math.random() * 255);
document.body.style.background = `rgb(${r}, ${g}, ${b})`
}
方式二:时间戳
window.onscroll = throttle(changColor, 1000);
// 时间戳
function throttle(fun, delay) {
let pre = 0;
return function() {
// 获取现在的时间戳
let now = new Date();
// 现在的时间戳 减去 上一次的时间戳 大于 设置的触发时间的话 才执行相应的逻辑
if(now - pre > delay) {
fun();
// 执行完逻辑之后 把 当前的时间now 赋值 pre(在下一次事件触发的时候作为上一次的时间戳)
pre = now;
}
}
function changColor() {
let r = Math.floor(Math.random() * 255);
let g = Math.floor(Math.random() * 255);
let b = Math.floor(Math.random() * 255);
document.body.style.background = `rgb(${r}, ${g}, ${b})`
}
效果图
perfect