func.js
3.47 KB
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
/**
* 防抖函数(debounce)
* 核心:触发后延迟执行,中途再次触发则重置延迟时间,只执行最后一次
* @param {Function} fn - 要防抖的目标函数
* @param {number} delay - 延迟时间(毫秒),默认500ms
* @param {boolean} immediate - 是否立即执行一次(第一次触发时执行,后续触发延迟),默认false
* @returns {Function} 包装后的防抖函数
*/
export function debounce(fn, delay = 500, immediate = false) {
let timer = null; // 存储定时器ID
// 返回包装后的函数
const debounced = function (...args) {
// 保存this指向(确保原函数this指向不变)
const context = this;
// 如果有正在等待的定时器,清除它(重置延迟)
if (timer) clearTimeout(timer);
// 立即执行的逻辑
if (immediate) {
// 是否已经执行过(第一次触发时执行)
const callNow = !timer;
// 设置定时器:delay时间后清空timer,允许下次触发立即执行
timer = setTimeout(() => {
timer = null;
}, delay);
// 第一次触发时执行函数
if (callNow) fn.apply(context, args);
} else {
// 非立即执行:每次触发都重置定时器,delay后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, delay);
}
};
// 新增取消防抖的方法(可选,用于手动终止)
debounced.cancel = function () {
clearTimeout(timer);
timer = null;
};
return debounced;
}
/**
* 节流函数(throttle)
* 核心:固定时间内只执行一次,到点必触发,不重置时间
* @param {Function} fn - 要节流的目标函数
* @param {number} interval - 执行间隔(毫秒),默认500ms
* @param {Object} options - 配置项
* @param {boolean} options.leading - 是否允许首次触发执行,默认true
* @param {boolean} options.trailing - 是否允许最后一次触发延迟执行,默认true
* @returns {Function} 包装后的节流函数
*/
export function throttle(fn, interval = 1000, options = { leading: true, trailing: true }) {
let timer = null; // 存储定时器ID
let lastCallTime = 0; // 上一次执行函数的时间
// 返回包装后的函数
const throttled = function (...args) {
const context = this;
const now = Date.now(); // 当前时间
// 如果禁用首次执行,且是第一次触发,初始化lastCallTime为当前时间
if (!lastCallTime && !options.leading) lastCallTime = now;
// 计算距离下次可执行的剩余时间
const remainingTime = interval - (now - lastCallTime);
// 剩余时间<=0:到了执行时间,直接执行
if (remainingTime <= 0) {
// 清除之前的定时器(防止trailing触发)
if (timer) {
clearTimeout(timer);
timer = null;
}
// 执行目标函数
fn.apply(context, args);
// 更新上一次执行时间
lastCallTime = now;
} else if (options.trailing && !timer) {
// 剩余时间>0,且允许最后一次执行:设置定时器延迟执行
timer = setTimeout(() => {
// 如果禁用首次执行,重置lastCallTime(避免重复触发)
lastCallTime = options.leading ? Date.now() : 0;
fn.apply(context, args);
timer = null;
}, remainingTime);
}
};
// 新增取消节流的方法(可选)
throttled.cancel = function () {
clearTimeout(timer);
timer = null;
lastCallTime = 0;
};
return throttled;
}