coder-Tom

一个喜欢代码, 音乐,读书, 跑步, 记录生活的程序员

0%

函数的防抖与节流

函数防抖和节流

什么是函数防抖?

短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行

而我们的函数防抖分为立即执行版和非立即执行版:

非立即执行版:

1
2
3
4
5
6
7
8
9
10
11
 function debounce(func, wait) {
let timeout;
return function () {
const context = this;
const args = [...arguments];
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
func.apply(context, args)
}, wait);
}
}

非立即执行版的意思是触发事件后函数不会立即执行,而是在 n 秒后执行,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。

立即执行版:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 立即执行版
function debounce(func, wait) {
let timer;
return function() {
let context = this; // 这边的 this 指向谁?
let args = arguments; // arguments中存着e

if (timer) clearTimeout(timer);

let callNow = !timer;

timer = setTimeout(() => {
timer = null;
}, wait)

if (callNow) func.apply(context, args);
}
}

立即执行版的意思是触发事件后函数会立即执行,然后 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
/**
* debounce:函数防抖
* @params
* func:要执行的函数
* wait:间隔时间
* immediate:触发的边界(TRUE==>开始边界)
* @return
* 可被调用的函数
*/
function debounce(func, wait, immediate) {
let timeout = null,
result = null
return function (...args) {
let now = immediate && !timeout
if(timeout)clearTimeout(timeout)
timeout = setTimeout(() => {
if (!immediate) result = func.call(this, ...args)
timeout = null
},wait)
if (now) result = func.call(this, ...args)
return result
}
}

我们常见的工具库, 比如说lodash中就对我们的这个函数防抖做了一个封装, 如果我们的在工作中遇到类似的需求, 就可以直接自己写一个或者是用人家的

函数防抖的主要使用场景:

函数防抖一般用在什么情况之下呢?一般用在,连续的事件只需触发一次回调的场合。具体有:

  • 搜索框搜索输入。只需用户最后一次输入完,再发送请求;
  • 用户名、手机号、邮箱输入验证;
  • 浏览器窗口大小改变后,只需窗口调整完后,再执行 resize 事件中的代码,防止重复渲染。

函数节流:

限制一个函数在一定时间内只能执行一次

主要实现思路就是通过 setTimeout 定时器,通过设置延时时间,在第一次调用时,创建定时器,先设定一个变量,然后把定时器赋值给这个变量,再写入需要执行的函数。第二次执行这个函数时,会判断变量是否true,是则返回。当第一次的定时器执行完函数最后会设定变量为false。那么下次判断变量时则为false,函数会依次运行。目的在于在一定的时间内,保证多次函数的请求只执行最后一次调用

节流也是有下面几个版本:

  1. 时间戳版本:函数立即执行,间隔wait秒

  2. 定时器版本:间隔wait秒,函数执行,结束后函数在执行一次

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* throttle:函数节流
* @version
* 时间戳版本
* @params
* fn:要执行的函数
* wait:间隔时间
*/
function throttle(fn, wait) {
let result = null,
per = null
return function (...args) {
let now = new Date
if (now - per > wait) {
result = fn.call(this, ...args)
per = now
}
return result
}
}

/**
* throttle:函数节流
* @version
* 定时器版本
* @params
* fn:要执行的函数
* wait:间隔时间
*/
function throttle(fn, wait) {
let timerout = null
return function (...args) {
if (!timerout) {
timerout = setTimeout(() => {
fn.call(this, ...args)
clearTimeout(timerout)
timerout = null
}, wait);
}
}
}

/**
* throttle:函数节流
* @version
* plus版本
* @params
* fn:要执行的函数
* wait:间隔时间
* @return
* 可被调用的函数
*/
function throttle(fn, wait) {
let result = null,
timerout = null,
pre = null
return function (...args) {
let now = new Date
remaining = wait - (now - pre)
if (remaining <= 0) {
pre = now
clearTimeout(timerout)
timerout = null
result = fn.call(this, ...args)
} else if (!timerout) {
timerout = setTimeout(() => {
pre = new Date
timerout = null
result = fn.call(this, ...args)
}, remaining);
}
return result
}
}

使用场景:

  • 懒加载、滚动加载、加载更多或监听滚动条位置;
  • 百度搜索框,搜索联想功能;
  • 防止高频点击提交,防止表单重复提交;