JS节流和防抖

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

节流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 时间戳
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()
}
}
}

// 定时器
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}

// 时间戳与定时器结合更加准确
function throttled3(fn, delay) {
let timer = null
let startTime = Date.now()
return function(){
let context = this
let args = arguments
let curentTime = Date.now()
let remainTime = delay - (curentTime - startTime)
clearTimeout(timer)
if (remainTime <= 0) {
fn.apply(context, args)
startTime = Date.now()
} else (
timer = setTimeout(fn, remainTime)
)
}
}

防抖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 简单版本
function debounce(fn, wait) {
let timer

return function() {
let context = this
let args = arguments
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}

// 防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:
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);
}
}
}

适用场景

  1. 防抖在连续的事件,只需触发一次回调的场景有:
  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
  • 手机号、邮箱验证输入检测
  • 窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
  1. 节流在间隔一段时间执行一次回调的场景有:
  • 滚动加载,加载更多或滚到底部监听
  • 搜索框,搜索联想功能
-------------本文结束&感谢您的阅读-------------