防抖 (debounce) :多次触发,只在最后一次触发时,执行目标函数。
节流(throttle)技能冷却中:限制目标函数调用的频率,比如:1s内不能调用2次。
举例子
假设调用闪现,d就是fn,是一个函数
const d = () =>{
consolo.log('闪现')
}
let 冷却中 = false
let timer = null
function sx() {
if(冷却中){return}
d()
冷却中 = true
timer = seTimeout(()=>{
冷却中 = false
},120*1000)
}
解释:
d()是一个函数,当调用d()函数时,就会打印闪现;- 如果调用
d(),就设置一个计时器,刚开始设置timer=null; - 设置一个120s的时间,
timer = setTimerout(()=>{},120*1000); - 120s之后,把冷却中置换一,先设置
let冷却中 = false; - 只要调用
d(),就把let 冷却中 = true,120s之后,就把let 冷却中 = false; - 调用
d()之前,先检查一下,if(冷却中){return},就什么也不做。 - 因为刚开始
let 冷却中 = false,所以可以调用d(); - 可以调用
d()之后,冷却中 = true,要等120s后,才可以变成false,函数运行;
const createFn = (f,time) = >{
return ()=>{
}
}
综合一下
const d = () =>{
console.log('闪现')
}
const createFn = (f,time) => {
let 冷却中 = false
let timer = null
return (...args)=>{
if(冷却中){return}
f(...args)
冷却中 = true
timer = setTimeout(()=>{
冷却中 = false
},time)
}
}
const d2 = createFn(d,120*1000)
正常版本
const d = () =>{
console.log('闪现')
}
const throttle = (f,time) => {
let flag = false
let timer = null
return (...args)=>{
if(flag){return}
f(...args)
flag = true
timer = setTimeout(()=>{
flag = false
},time)
}
}
const d2 = throttle(d,120*1000)
使用场景
比如绑定响应鼠标移动、窗口大小调整、滚屏等事件时,绑定的函数触发的频率会很频繁。若稍处理函数微复杂,需要较多的运算执行时间和资源,往往会出现延迟,甚至导致假死或者卡顿感。为了优化性能,这时就很有必要使用 debounce 或 throttle 了。
// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {
// 上一次执行 fn 的时间
let previous = 0
// 将 throttle 处理结果当作函数返回
return function(...args) {
// 获取当前时间,转换成时间戳,单位毫秒
let now = +new Date()
// 将当前时间和上一次执行函数的时间进行对比
// 大于等待时间就把 previous 设置为当前时间并执行函数 fn
if (now - previous > wait) {
previous = now
fn.apply(this, args)
}
}
}
// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)
// 节流就是「技能冷却中」
const throttle = (fn, time) => {
let 冷却中 = false return (...args) => {
if(冷却中) return fn.call(undefined, ...args) 冷却中 = true setTimeout(()=>{ 冷却中 = false }, time) } }
// 还有一个版本是 在冷却结束时调用 fn
// 简洁版,删掉冷却中变量,直接使用 timer 代替
const throttle = (f, time) => {
let timer = null return (...args) => {
if(timer) {return} f.call(undefined, ...args) timer = setTimeout(()=>{ timer = null }, time) } }