前端笔记:节流和防抖

# 区别

节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时

# 应用场景

节流:滚动条监听、搜索框输入
防抖:输入框搜索、窗口大小 resize

# 实现

节流:

  • 一定时间内的无论点击多少次,都只会执行第一次,其余的直接 return
1
2
3
4
5
6
7
8
9
10
function throttled1(fn, delay = 500) {
let oldtime = Date.now()
return function (...args) {
let newtime = Date.now()
if (newtime - oldtime >= delay) {
fn.apply(null, args)
oldtime = Date.now()
}
}
}
1
2
3
4
5
6
7
8
9
10
11
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function throttled(fn, delay) {
let timer = null
let starttime = Date.now()
return function () {
let curTime = Date.now() // 当前时间
let remaining = delay - (curTime - starttime) // 从上一次到现在,还剩下多少多余时间
let context = this
let args = arguments
clearTimeout(timer)
if (remaining <= 0) {
fn.apply(context, args)
starttime = Date.now()
} else {
timer = setTCSSimeout(fn, remaining);
}
}
}

防抖:

1
2
3
4
5
6
7
8
9
10
11
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout 不为null
if (immediate) {
let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
timeout = setTimeout(function () {
timeout = null;
}, wait)
if (callNow) {
func.apply(context, args)
}
}
else {
timeout = setTimeout(function () {
func.apply(context, args)
}, wait);
}
}
}