简单的防抖
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14// 一个最简单的防抖 function debounce(fun, wait = 50) { let timer; return function (...args) { // 有新的请求进来就干掉原来的计时器,重新开始计时 if (timer) { clearTimeout(timer); } // 计时器完成,执行函数 timer = setTimeout(() => { fun.apply(this, args); }, 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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120/** * 一个简单的节流函数 * @param {function} fun 需要执行的函数 * @param {number} time 指定的时间周期长度(毫秒) */ export function easyThrottle(fun, time = 500) { console.log(fun, time); // 用于缓存当前时间,以判断上一次这个方法执行到现在已经用了多久 let previous = 0; // 返回一个闭包函数 return function (...args) { // 当前时间 let now = Date.now(); // 上次执行时间到当前时间是否已经允许再次执行 if (now - previous > time) { // 执行函数 fun.apply(this, args); // 修改上次时间为当前时间,下一次进入时就跟当前时间比较 previous = now; } }; } /** * 1. 建立一个变量timer,用于储存当次执行的时间,如果未执行过,则为0 * 2. 当接受到函数的时候,获取一个当前系统时间,用这个时间与上面的变量作比较,当它们的差值超出设定的延时时间后,执行事件处理函数 * 3. 修改变量timer的值,让它等于当前的系统时间,用于标记在这个时间已经执行过事件处理函数 */ /** * 然后再实现一个考虑比较周全的节流 * * @param {function} func 需要执行的方法 * @param {number} wait 时间周期 * @param {object} options 配置项 * @param {boolean} options.leading 第一次调用函数时是否需要执行 * @param {boolean} options.trailing 最后一次调用函数时是否需要执行 */ export function throttle( func, wait = 500, options = { leading: false, trailing: true } ) { // 如果第一次调用和最后一次调用都为false,可能会出现用户操作完全无响应的情况 if (!options.leading && !options.trailing) { console.warn("options的leading属性和trailing属性,至少要有一个为true!"); options.trailing = true; } // 缓存一个定时器,便于执行最后一次任务 let timer; // 缓存上一次执行回调的时间 let previous = 0; /** * 抛出的闭包函数,外部每次触发事件回调都会执行这个函数 * @param {...any} args 接受的参数,比如e.target.value */ function throttled(...args) { // 记录当前时间 let now = Date.now(); let remaining; // 是否是第一次调用回调函数(previous只在首次调用时为0,其它时间应该都是上次执行时间) if (previous === 0) { previous = now; // 判断是否需要首次调用(这里与上面的第一次调用不是一个概念) // 不需要首次调用的,等待一个时间周期 if (!options.leading) { remaining = wait; } // 首次调用的直接执行 else { remaining = 0; } } // 不是第一次进入,直接拿上一次的时间与当前时间进行计算 else { remaining = wait - (now - previous); } // 等待时间为0,表示需要立即调用函数 if (remaining <= 0) { // 如果有定时器,表示有一个定时器在执行最后一次调用延时执行的方法,所以这里需要清除掉它 if (timer) { // 停止计时器并手动清空防止内存泄漏 clearTimeout(timer); timer = null; } // 设置 previous 为当前时间 previous = now; // 执行 func 函数 func.apply(this, args); } // 等待时间不为0的时候,我们需要先判断是否需要执行最后一次调用 else if (options.trailing) { // 需要清除上一次的定时任务 clearTimeout(timer); /** * 最后一次调用执行的方法(只有options.trailing为true时才有效) * @param {*} context 当前上下文,表示this * @param {*} args 当前调用时传入的参数,比如e.target.value */ timer = setTimeout(() => { // 因为这是尾调用,表示下一次再来调用可能需要较长一段时间了, // 应该算是一个新的调用过程,所以设定 previous = 0 previous = 0; // 停止计时器并手动清空防止内存泄漏 clearTimeout(timer); timer = null; // 执行函数 func.apply(this, args); }, remaining); } // 其它还在等待的状态则忽略 } // 手动取消 throttled.cancel = function () { clearTimeout(timer); timer = null; previous = 0; }; return throttled; }
useDebounce
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14import { useRef, useState } from "react"; export function useDebounce(params, delay = 500) { const [data, setData] = useState(params) //用来存储计时器 const timer = useRef(null) const debounce = useRef((args) => { // 有新的请求就清除timer.current中的计时器,重新开始计时 if (timer.current) { clearTimeout(timer.current) } timer.current = setTimeout(() => setData(args), delay) }) return [data, debounce.current] }
useThrottle
复制代码
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
49import { useState, useRef, useCallback } from "react" //data 默认值, delay 间隔时间 ,leading首次是否触发 ,trainling最后一次是否触发 export function useThrottle(param, config = { delay: 1000, leading: false, trailing: true }) { const [data, setData] = useState(param) //缓存上次执行的setstate方法和计时器 const setting = useRef({ prevTime: 0, timer: null }).current //清除计时器 const clearTimer = useCallback(() => { if (setting.timer) { clearTimeout(setting.timer) setting.timer = null } }, [setting]) //修改上次执行setState的时间并修改state const applyFun = useCallback( (args, now = 0) => { setting.prevTime = now setData(args) }, [setting] ) // 返回给用户的方法,注册后永不改变 const throttle = useRef((args) => { //获取当前时间 let now = Date.now() //当第一次触发且首次不触发时 if (!setting.prevTime && !config.leading) { setting.prevTime = now } //距离下次触发的时间 let remaining = config.delay - (now - setting.prevTime) //清除计时器 clearTimer() // 差值小于等于零则立即执行 if (remaining <= 0) { console.log(args, now); applyFun(args, now) } //如果最后一次触发 if (config.trailing) { setting.timer = setTimeout(() => { applyFun(args) //调用结束后清除上次调用时间为0等待下次使用 setting.prevTime = 0 }, remaining) } }) return [data, throttle.current] }
最后
以上就是精明草丛最近收集整理的关于自定义Hooks(防抖,节流)简单的防抖简单的节流useDebounce的全部内容,更多相关自定义Hooks(防抖,节流)简单内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复