节流,防抖
防抖案例:百度搜索,有用户输入不会每次发起请求当用户输入完等0.2s再发起请求,resize改变浏览器大小
节流案例:拖拽一个元素时我们要随时拿到该元素拖拽的位置, 直接用drag事件则会频繁触发很容易卡顿,节流是无论拖拽多快,我们设定每隔100ms触发一次、
<input type="text" class="input1">
let input1 = document.querySelector('.input1')
// 监听一个键盘按下事件
// input1.addEventListener('keyup',function() {
// console.log(input1.value);
// })
// let timer = null
// input1.addEventListener('keyup',function() {
// if (timer) {
// console.log('timer',timer);
// clearTimeout(timer)
// }
// // 定时器会返回一个id 赋值给timer
// timer = setTimeout(() =>{
// // 模拟触发change 事件,真实的是发请求
// console.log(input1.value);
// // 清空定时器
// timer = null
// },500)
// })
/*
分析逻辑
场景1. 输入1的时候,被keyup监听到,此时无定时器id 不进入判断语句,有定时任务 返回定时器id,进入判断语句, 等待0.5s 触发定时任务
场景2. 输入123的时候,1被keyup监听到,此时无定时器id 不进入判断语句,有定时任务返回定时器id,进入判断语句,
正在等待0.5s 触发定时任务,此时又输入2被keyup监听到,此时有定时器id进入判断语句清空id,正在等待0.5s 触发定时任务
此时又输入3被keyup监听到,此时有定时器id进入判断语句清空id,等待0.5s 触发定时任务,等待中没有监听到,至0.5s时触发定时任务
*/
// 回忆下接收一个函数作为参数的情况
// function run(fn,delay=500) {
// return function() {
// fn()
// }
// }
// run(()=>{console.log(1)})()
// run(function(){console.log(2)})()
// 若有多个input需要做防抖,我们肯定是需要封装成一个函数的额
// 防抖
function debounce(fn ,delay = 500) {
// 此时的timer是在闭包中,为什么我们需要接收一个函数作为参数?,因为我们不希望我们内部逻辑的数据被修改,而且又能在其他作用域使用
// 故我们采用闭包的形式,这里也是一个闭包的使用场景之-
let timer = null
// 返回一个函数
return function() {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() =>{
// fn()
// 完整写法
fn.apply(this, arguments)
timer = null
}, delay)
}
}
// 这里需要注意箭头函数
// input1.addEventListener('keyup', debounce(()=>{
// console.log(input1.value);
// }),delay=600)
input1.addEventListener('keyup', debounce(function(){
console.log(input1.value);
}),600)
.div1 {
width: 200px;
height: 200px;
background-color: pink;
}
<div class="div1" draggable="true">
可拖拽
</div>
let div1 = document.querySelector('.div1')
// 监听拖拽事件,不使用节流直接非常卡
// div1.addEventListener('drag',function(e) {
// console.log(e.offsetX, e.offsetY);
// })
// 节流
function throttle(fn, delay=100) {
let timer = null
return function() {
if (timer) {
return
}
timer = setTimeout(() =>{
// fn()
fn.apply(this, arguments)
timer = null
},delay)
}
}
// 此时我们使用fn()时文们的函数就会报错!!! 值传入的问题
// div1.addEventListener('drag', throttle(function(e) {
// console.log(e.offsetX, e.offsetY);
// }),5000)
div1.addEventListener('drag', throttle(function(e) {
console.log(e.offsetX, e.offsetY);
}),5000)
应用场景:
一、防抖
防抖策略(debounce
)是当事件被触发后,延迟n
秒后再执行回调,如果在这n
秒内事件又被触发,则重新计时。
好处: 能够保证用户在频繁触发某些事件的时候,不会频繁的执行回调,只会被执行一次
防抖的应用场景
用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源;
防抖的实现思路
二、节流
节流策略(throttle
),顾名思义,可以减少一段时间内事件的触发频率。
规定一个单位时间内,只能触发一次函数,如果单位时间内触发多次函数,只有一次才生效
节流的应用场景
① 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;
② 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源;
节流的实现思路
let flag = true;
if (flag) {
// 进入条件后 改变flag的值为false
flag = false
// 定义一个延时函数 在最后把flag的值变为true
// 这样就可以确保每秒 函数只会执行一次
setTimeout(function(){
console.log(1);
...执行函数
flag = true
},1000)
}