@cloudcome/utils-core 1.20.0 → 1.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -72
- package/dist/array.cjs.map +1 -1
- package/dist/array.mjs.map +1 -1
- package/dist/async.cjs.map +1 -1
- package/dist/async.mjs.map +1 -1
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.mjs.map +1 -1
- package/dist/color.cjs.map +1 -1
- package/dist/color.mjs.map +1 -1
- package/dist/date.cjs.map +1 -1
- package/dist/date.mjs.map +1 -1
- package/dist/dict.cjs +1 -1
- package/dist/dict.cjs.map +1 -1
- package/dist/dict.mjs +1 -1
- package/dist/dict.mjs.map +1 -1
- package/dist/easing.cjs +1 -2
- package/dist/easing.cjs.map +1 -1
- package/dist/easing.mjs +1 -2
- package/dist/easing.mjs.map +1 -1
- package/dist/emitter.cjs.map +1 -1
- package/dist/emitter.mjs.map +1 -1
- package/dist/env.cjs.map +1 -1
- package/dist/env.mjs.map +1 -1
- package/dist/error.cjs.map +1 -1
- package/dist/error.mjs.map +1 -1
- package/dist/exception.cjs.map +1 -1
- package/dist/exception.mjs.map +1 -1
- package/dist/function.cjs +33 -0
- package/dist/function.cjs.map +1 -1
- package/dist/function.d.ts +34 -0
- package/dist/function.mjs +33 -1
- package/dist/function.mjs.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/object/get-set.d.ts +1 -25
- package/dist/object.cjs.map +1 -1
- package/dist/object.mjs.map +1 -1
- package/dist/promise.cjs.map +1 -1
- package/dist/promise.mjs.map +1 -1
- package/dist/qs.cjs.map +1 -1
- package/dist/qs.mjs.map +1 -1
- package/dist/regexp.cjs.map +1 -1
- package/dist/regexp.mjs.map +1 -1
- package/dist/string2.cjs.map +1 -1
- package/dist/string2.mjs.map +1 -1
- package/dist/time.cjs.map +1 -1
- package/dist/time.mjs.map +1 -1
- package/dist/timer.cjs +76 -32
- package/dist/timer.cjs.map +1 -1
- package/dist/timer.d.ts +130 -25
- package/dist/timer.mjs +76 -32
- package/dist/timer.mjs.map +1 -1
- package/dist/tree.cjs.map +1 -1
- package/dist/tree.mjs.map +1 -1
- package/dist/try.cjs.map +1 -1
- package/dist/try.mjs.map +1 -1
- package/dist/type.cjs.map +1 -1
- package/dist/type.mjs.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/url.cjs +1 -1
- package/dist/url.cjs.map +1 -1
- package/dist/url.mjs +1 -1
- package/dist/url.mjs.map +1 -1
- package/package.json +6 -6
package/dist/timer.cjs
CHANGED
|
@@ -5,13 +5,29 @@ var STATUS_START = 1;
|
|
|
5
5
|
var STATUS_PAUSE = 2;
|
|
6
6
|
var STATUS_STOP = 3;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* 创建可控制的间隔定时器核心函数
|
|
9
9
|
*
|
|
10
|
-
* @
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // 无 condition,state.data 为 null
|
|
13
|
+
* makeInterval({
|
|
14
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
15
|
+
* runner: (state) => console.log(state.times),
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* // 有 condition,T 自动推断为 number
|
|
19
|
+
* makeInterval({
|
|
20
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
21
|
+
* condition: (state) => state.times,
|
|
22
|
+
* runner: (state) => state.data.toFixed(2),
|
|
23
|
+
* })
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param options - 配置选项
|
|
27
|
+
* @returns 定时器控制方法集合
|
|
13
28
|
*/
|
|
14
|
-
function makeInterval(
|
|
29
|
+
function makeInterval(options) {
|
|
30
|
+
const { dispatcher, runner, condition, leading, trailing } = options;
|
|
15
31
|
let startAt = 0;
|
|
16
32
|
let lastAt = 0;
|
|
17
33
|
let stopAt = 0;
|
|
@@ -20,14 +36,14 @@ function makeInterval(nextTime, effect) {
|
|
|
20
36
|
let times = 0;
|
|
21
37
|
let status = STATUS_READY;
|
|
22
38
|
let runningTime = 0;
|
|
23
|
-
const execute = () => {
|
|
39
|
+
const execute = async () => {
|
|
24
40
|
if (status >= STATUS_PAUSE) return;
|
|
25
41
|
const now = Date.now();
|
|
26
42
|
const intervalTime = lastAt > 0 ? now - lastAt : 0;
|
|
27
43
|
runningTime += intervalTime;
|
|
28
44
|
lastAt = now;
|
|
29
45
|
const state = {
|
|
30
|
-
times
|
|
46
|
+
times,
|
|
31
47
|
startAt,
|
|
32
48
|
stopAt,
|
|
33
49
|
pauseAt,
|
|
@@ -35,32 +51,38 @@ function makeInterval(nextTime, effect) {
|
|
|
35
51
|
currentAt: now,
|
|
36
52
|
elapsedTime: startAt > 0 ? now - startAt : 0,
|
|
37
53
|
runningTime,
|
|
38
|
-
intervalTime
|
|
54
|
+
intervalTime,
|
|
55
|
+
data: null
|
|
39
56
|
};
|
|
40
|
-
if (
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
nextTime(execute);
|
|
57
|
+
if (condition) try {
|
|
58
|
+
state.data = await condition(state);
|
|
59
|
+
} catch {
|
|
60
|
+
dispatcher(execute);
|
|
61
|
+
return;
|
|
46
62
|
}
|
|
63
|
+
state.times = ++times;
|
|
64
|
+
await runner(state);
|
|
65
|
+
dispatcher(execute);
|
|
47
66
|
};
|
|
48
67
|
const canStart = () => status === STATUS_READY;
|
|
49
68
|
const start = () => {
|
|
50
69
|
if (!canStart()) return;
|
|
51
70
|
status = STATUS_START;
|
|
52
71
|
startAt = Date.now();
|
|
53
|
-
|
|
72
|
+
if (leading === false) dispatcher(execute);
|
|
73
|
+
else execute();
|
|
54
74
|
};
|
|
55
75
|
const canStop = () => status === STATUS_START;
|
|
56
76
|
const stop = () => {
|
|
57
77
|
if (!canStop()) return;
|
|
78
|
+
if (trailing) execute();
|
|
58
79
|
status = STATUS_STOP;
|
|
59
80
|
stopAt = Date.now();
|
|
60
81
|
};
|
|
61
82
|
const canPause = () => status === STATUS_START;
|
|
62
83
|
const pause = () => {
|
|
63
84
|
if (!canPause()) return;
|
|
85
|
+
if (trailing) execute();
|
|
64
86
|
status = STATUS_PAUSE;
|
|
65
87
|
pauseAt = Date.now();
|
|
66
88
|
};
|
|
@@ -85,45 +107,67 @@ function makeInterval(nextTime, effect) {
|
|
|
85
107
|
};
|
|
86
108
|
}
|
|
87
109
|
/**
|
|
88
|
-
*
|
|
110
|
+
* 创建基于 setTimeout 的间隔定时器
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* // 无 condition
|
|
115
|
+
* timerInterval({
|
|
116
|
+
* interval: 1000,
|
|
117
|
+
* runner: (state) => console.log(state.times),
|
|
118
|
+
* })
|
|
119
|
+
*
|
|
120
|
+
* // 有 condition,T 自动推断为 number
|
|
121
|
+
* timerInterval({
|
|
122
|
+
* interval: 1000,
|
|
123
|
+
* condition: (state) => state.times,
|
|
124
|
+
* runner: (state) => state.data.toFixed(2),
|
|
125
|
+
* })
|
|
126
|
+
* ```
|
|
89
127
|
*
|
|
90
|
-
* @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数
|
|
91
|
-
* @param interval - 间隔时间,单位为毫秒
|
|
92
128
|
* @param options - 配置选项
|
|
93
|
-
* @returns
|
|
129
|
+
* @returns 定时器控制方法集合
|
|
94
130
|
*/
|
|
95
|
-
function
|
|
131
|
+
function timerInterval(options) {
|
|
132
|
+
const { runner, interval, condition, leading, trailing } = options;
|
|
96
133
|
let timeId;
|
|
97
|
-
const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval(
|
|
98
|
-
|
|
99
|
-
|
|
134
|
+
const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({
|
|
135
|
+
dispatcher: (dispatch) => {
|
|
136
|
+
timeId = setTimeout(dispatch, interval);
|
|
137
|
+
},
|
|
138
|
+
runner,
|
|
139
|
+
condition,
|
|
140
|
+
leading: leading ?? false,
|
|
141
|
+
trailing
|
|
142
|
+
});
|
|
100
143
|
return {
|
|
101
144
|
start() {
|
|
102
145
|
if (!canStart()) return;
|
|
103
|
-
|
|
104
|
-
else timeId = setTimeout(start, interval);
|
|
146
|
+
start();
|
|
105
147
|
},
|
|
106
148
|
stop() {
|
|
107
149
|
if (!canStop()) return;
|
|
108
|
-
if (options?.trailing) execute();
|
|
109
|
-
clearTimeout(timeId);
|
|
110
150
|
stop();
|
|
151
|
+
clearTimeout(timeId);
|
|
111
152
|
},
|
|
112
153
|
pause() {
|
|
113
154
|
if (!canPause()) return;
|
|
114
|
-
if (options?.trailing) execute();
|
|
115
|
-
clearTimeout(timeId);
|
|
116
155
|
pause();
|
|
156
|
+
clearTimeout(timeId);
|
|
117
157
|
},
|
|
118
158
|
resume(immediate) {
|
|
119
159
|
if (!canResume()) return;
|
|
120
|
-
if (immediate ||
|
|
121
|
-
else timeId = setTimeout(resume, interval);
|
|
160
|
+
if (immediate || leading) resume();
|
|
161
|
+
else timeId = setTimeout(() => resume(), interval);
|
|
162
|
+
},
|
|
163
|
+
execute() {
|
|
164
|
+
clearTimeout(timeId);
|
|
165
|
+
execute();
|
|
122
166
|
}
|
|
123
167
|
};
|
|
124
168
|
}
|
|
125
169
|
//#endregion
|
|
126
170
|
exports.makeInterval = makeInterval;
|
|
127
|
-
exports.
|
|
171
|
+
exports.timerInterval = timerInterval;
|
|
128
172
|
|
|
129
173
|
//# sourceMappingURL=timer.cjs.map
|
package/dist/timer.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.cjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n *
|
|
1
|
+
{"version":3,"file":"timer.cjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["import type { MaybePromise } from './types';\n\n/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => MaybePromise<unknown>)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * @param next - 可选的手动触发下一次调度的函数\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>, next?: () => void) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner: runner as (timer: TimerState<T>) => MaybePromise<unknown>,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";;AAwGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAuB;GAC3B;GACA;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACA,MAAM;GACP;EAED,IAAI,WACF,IAAI;GACF,MAAM,OAAO,MAAM,UAAU,MAAM;UAC7B;GACN,WAAW,QAAQ;GACnB;;EAIJ,MAAM,QAAQ,EAAE;EAEhB,MAAO,OAA2D,MAAM;EACxE,WAAW,QAAQ;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,SAAS;EACT,UAAU,KAAK,KAAK;EACpB,IAAI,YAAY,OACd,WAAW,QAAQ;OAEnB,SAAS;;CAIb,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,SAAS,EAAE;EAChB,IAAI,UAAU,SAAS;EACvB,SAAS;EACT,SAAS,KAAK,KAAK;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,IAAI,UAAU,SAAS;EACvB,SAAS;EACT,UAAU,KAAK,KAAK;;CAGtB,MAAM,kBAAkB,WAAW;CACnC,MAAM,eAAe;EACnB,IAAI,CAAC,WAAW,EAAE;EAClB,SAAS;EACT,WAAW,KAAK,KAAK;EACrB,SAAS;EACT,SAAS;;CAGX,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;;;;;;;;;;;;;;;;;;;;AAsDH,SAAgB,cAAwB,SAAgD;CACtF,MAAM,EAAE,QAAQ,UAAU,WAAW,SAAS,aAAa;CAC3D,IAAI;CACJ,MAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,YAAY,aAAa;EACnG,aAAa,aAAa;GACxB,SAAS,WAAW,UAAU,SAAS;;EAEjC;EACR;EACA,SAAS,WAAW;EACpB;EACD,CAAC;CAEF,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,OAAO;;EAGT,OAAO;GACL,IAAI,CAAC,SAAS,EAAE;GAChB,MAAM;GACN,aAAa,OAAO;;EAGtB,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,OAAO;GACP,aAAa,OAAO;;EAGtB,OAAO,WAAqB;GAC1B,IAAI,CAAC,WAAW,EAAE;GAClB,IAAI,aAAa,SACf,QAAQ;QAER,SAAS,iBAAiB,QAAQ,EAAE,SAAS;;EAIjD,UAAU;GACR,aAAa,OAAO;GACpB,SAAS;;EAEZ"}
|
package/dist/timer.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* 定时器状态基础接口
|
|
3
3
|
*/
|
|
4
|
-
export type
|
|
4
|
+
export type TimerStateBase = {
|
|
5
5
|
/**
|
|
6
6
|
* 执行次数
|
|
7
7
|
*/
|
|
@@ -39,58 +39,163 @@ export type TimerState = {
|
|
|
39
39
|
*/
|
|
40
40
|
intervalTime: number;
|
|
41
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* 定时器状态接口
|
|
44
|
+
* @template T - condition 函数返回值类型,默认为 unknown
|
|
45
|
+
*/
|
|
46
|
+
export type TimerState<T = unknown> = TimerStateBase & {
|
|
47
|
+
/**
|
|
48
|
+
* condition 函数返回值,未传入 condition 时为 null
|
|
49
|
+
*/
|
|
50
|
+
data: T;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* 定时器控制方法集合
|
|
54
|
+
*/
|
|
42
55
|
export type TimerHandler = {
|
|
43
56
|
/**
|
|
44
|
-
*
|
|
57
|
+
* 启动定时器
|
|
45
58
|
*/
|
|
46
59
|
start: () => void;
|
|
47
60
|
/**
|
|
48
|
-
*
|
|
61
|
+
* 暂停定时器
|
|
49
62
|
*/
|
|
50
63
|
pause: () => void;
|
|
51
64
|
/**
|
|
52
|
-
*
|
|
65
|
+
* 恢复定时器
|
|
66
|
+
* @param immediate - 是否立即执行一次
|
|
53
67
|
*/
|
|
54
68
|
resume: (immediate?: boolean) => void;
|
|
55
69
|
/**
|
|
56
|
-
*
|
|
70
|
+
* 停止定时器
|
|
57
71
|
*/
|
|
58
72
|
stop: () => void;
|
|
73
|
+
/**
|
|
74
|
+
* 清除上一次定时器,立即执行,并开始下一次定时器
|
|
75
|
+
*/
|
|
76
|
+
execute: () => void;
|
|
59
77
|
};
|
|
60
78
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* @param nextTime - 用于安排下一次执行的函数
|
|
64
|
-
* @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数
|
|
65
|
-
* @returns 返回包含控制方法的对象
|
|
79
|
+
* 间隔定时器控制方法集合,包含状态查询方法
|
|
66
80
|
*/
|
|
67
|
-
export
|
|
81
|
+
export type IntervalHandler = TimerHandler & {
|
|
82
|
+
/**
|
|
83
|
+
* 是否可以启动(处于 READY 状态)
|
|
84
|
+
*/
|
|
68
85
|
canStart: () => boolean;
|
|
86
|
+
/**
|
|
87
|
+
* 是否可以停止(处于 START 状态)
|
|
88
|
+
*/
|
|
69
89
|
canStop: () => boolean;
|
|
90
|
+
/**
|
|
91
|
+
* 是否可以暂停(处于 START 状态)
|
|
92
|
+
*/
|
|
70
93
|
canPause: () => boolean;
|
|
94
|
+
/**
|
|
95
|
+
* 是否可以恢复(处于 PAUSE 状态)
|
|
96
|
+
*/
|
|
71
97
|
canResume: () => boolean;
|
|
72
|
-
start: () => void;
|
|
73
|
-
stop: () => void;
|
|
74
|
-
pause: () => void;
|
|
75
|
-
resume: () => void;
|
|
76
|
-
execute: () => void;
|
|
77
98
|
};
|
|
78
|
-
|
|
99
|
+
/**
|
|
100
|
+
* makeInterval 配置选项
|
|
101
|
+
* @template T - condition 函数返回值类型
|
|
102
|
+
*/
|
|
103
|
+
export type MakeIntervalOptions<T> = {
|
|
104
|
+
/**
|
|
105
|
+
* 调度器函数,用于安排下一次执行
|
|
106
|
+
*/
|
|
107
|
+
dispatcher: (dispatch: () => void) => unknown;
|
|
108
|
+
/**
|
|
109
|
+
* 条件函数,每次执行前调用,返回值存入 state.data
|
|
110
|
+
* 使用 MaybePromise 支持同步或异步条件判断
|
|
111
|
+
* 抛错时跳过本次 runner 执行,继续下一次调度
|
|
112
|
+
*/
|
|
113
|
+
condition?: (state: TimerStateBase) => T;
|
|
114
|
+
/**
|
|
115
|
+
* 执行函数,每次定时器触发时调用,接收完整的定时器状态
|
|
116
|
+
* 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断
|
|
117
|
+
*/
|
|
118
|
+
runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;
|
|
119
|
+
/**
|
|
120
|
+
* 是否在定时器启动时立即执行一次,默认为 true
|
|
121
|
+
*/
|
|
122
|
+
leading?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* 是否在定时器停止或暂停时额外执行一次(trailing edge)
|
|
125
|
+
*/
|
|
126
|
+
trailing?: boolean;
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* 创建可控制的间隔定时器核心函数
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```typescript
|
|
133
|
+
* // 无 condition,state.data 为 null
|
|
134
|
+
* makeInterval({
|
|
135
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
136
|
+
* runner: (state) => console.log(state.times),
|
|
137
|
+
* })
|
|
138
|
+
*
|
|
139
|
+
* // 有 condition,T 自动推断为 number
|
|
140
|
+
* makeInterval({
|
|
141
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
142
|
+
* condition: (state) => state.times,
|
|
143
|
+
* runner: (state) => state.data.toFixed(2),
|
|
144
|
+
* })
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @param options - 配置选项
|
|
148
|
+
* @returns 定时器控制方法集合
|
|
149
|
+
*/
|
|
150
|
+
export declare function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler;
|
|
151
|
+
/**
|
|
152
|
+
* timerInterval 配置选项
|
|
153
|
+
* @template T - condition 函数返回值类型
|
|
154
|
+
*/
|
|
155
|
+
export type TimerIntervalOptions<T> = {
|
|
156
|
+
/**
|
|
157
|
+
* 间隔时间,单位为毫秒
|
|
158
|
+
*/
|
|
159
|
+
interval: number;
|
|
160
|
+
/**
|
|
161
|
+
* 条件函数,每次执行前调用,返回值存入 state.data
|
|
162
|
+
* 抛错时跳过本次 runner 执行,继续下一次调度
|
|
163
|
+
*/
|
|
164
|
+
condition?: (state: TimerStateBase) => T;
|
|
79
165
|
/**
|
|
80
|
-
*
|
|
166
|
+
* 执行函数,每次定时器触发时调用,接收完整的定时器状态
|
|
167
|
+
* @param next - 可选的手动触发下一次调度的函数
|
|
168
|
+
*/
|
|
169
|
+
runner: (state: TimerState<NoInfer<Awaited<T>>>, next?: () => void) => unknown;
|
|
170
|
+
/**
|
|
171
|
+
* 是否在定时器启动时立即执行一次,默认为 false
|
|
81
172
|
*/
|
|
82
173
|
leading?: boolean;
|
|
83
174
|
/**
|
|
84
|
-
*
|
|
175
|
+
* 是否在定时器停止或暂停时额外执行一次(trailing edge)
|
|
85
176
|
*/
|
|
86
177
|
trailing?: boolean;
|
|
87
178
|
};
|
|
88
179
|
/**
|
|
89
|
-
*
|
|
180
|
+
* 创建基于 setTimeout 的间隔定时器
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* // 无 condition
|
|
185
|
+
* timerInterval({
|
|
186
|
+
* interval: 1000,
|
|
187
|
+
* runner: (state) => console.log(state.times),
|
|
188
|
+
* })
|
|
189
|
+
*
|
|
190
|
+
* // 有 condition,T 自动推断为 number
|
|
191
|
+
* timerInterval({
|
|
192
|
+
* interval: 1000,
|
|
193
|
+
* condition: (state) => state.times,
|
|
194
|
+
* runner: (state) => state.data.toFixed(2),
|
|
195
|
+
* })
|
|
196
|
+
* ```
|
|
90
197
|
*
|
|
91
|
-
* @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数
|
|
92
|
-
* @param interval - 间隔时间,单位为毫秒
|
|
93
198
|
* @param options - 配置选项
|
|
94
|
-
* @returns
|
|
199
|
+
* @returns 定时器控制方法集合
|
|
95
200
|
*/
|
|
96
|
-
export declare function
|
|
201
|
+
export declare function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler;
|
package/dist/timer.mjs
CHANGED
|
@@ -4,13 +4,29 @@ var STATUS_START = 1;
|
|
|
4
4
|
var STATUS_PAUSE = 2;
|
|
5
5
|
var STATUS_STOP = 3;
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* 创建可控制的间隔定时器核心函数
|
|
8
8
|
*
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```typescript
|
|
11
|
+
* // 无 condition,state.data 为 null
|
|
12
|
+
* makeInterval({
|
|
13
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
14
|
+
* runner: (state) => console.log(state.times),
|
|
15
|
+
* })
|
|
16
|
+
*
|
|
17
|
+
* // 有 condition,T 自动推断为 number
|
|
18
|
+
* makeInterval({
|
|
19
|
+
* dispatcher: (dispatch) => setTimeout(dispatch, 1000),
|
|
20
|
+
* condition: (state) => state.times,
|
|
21
|
+
* runner: (state) => state.data.toFixed(2),
|
|
22
|
+
* })
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @param options - 配置选项
|
|
26
|
+
* @returns 定时器控制方法集合
|
|
12
27
|
*/
|
|
13
|
-
function makeInterval(
|
|
28
|
+
function makeInterval(options) {
|
|
29
|
+
const { dispatcher, runner, condition, leading, trailing } = options;
|
|
14
30
|
let startAt = 0;
|
|
15
31
|
let lastAt = 0;
|
|
16
32
|
let stopAt = 0;
|
|
@@ -19,14 +35,14 @@ function makeInterval(nextTime, effect) {
|
|
|
19
35
|
let times = 0;
|
|
20
36
|
let status = STATUS_READY;
|
|
21
37
|
let runningTime = 0;
|
|
22
|
-
const execute = () => {
|
|
38
|
+
const execute = async () => {
|
|
23
39
|
if (status >= STATUS_PAUSE) return;
|
|
24
40
|
const now = Date.now();
|
|
25
41
|
const intervalTime = lastAt > 0 ? now - lastAt : 0;
|
|
26
42
|
runningTime += intervalTime;
|
|
27
43
|
lastAt = now;
|
|
28
44
|
const state = {
|
|
29
|
-
times
|
|
45
|
+
times,
|
|
30
46
|
startAt,
|
|
31
47
|
stopAt,
|
|
32
48
|
pauseAt,
|
|
@@ -34,32 +50,38 @@ function makeInterval(nextTime, effect) {
|
|
|
34
50
|
currentAt: now,
|
|
35
51
|
elapsedTime: startAt > 0 ? now - startAt : 0,
|
|
36
52
|
runningTime,
|
|
37
|
-
intervalTime
|
|
53
|
+
intervalTime,
|
|
54
|
+
data: null
|
|
38
55
|
};
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
nextTime(execute);
|
|
56
|
+
if (condition) try {
|
|
57
|
+
state.data = await condition(state);
|
|
58
|
+
} catch {
|
|
59
|
+
dispatcher(execute);
|
|
60
|
+
return;
|
|
45
61
|
}
|
|
62
|
+
state.times = ++times;
|
|
63
|
+
await runner(state);
|
|
64
|
+
dispatcher(execute);
|
|
46
65
|
};
|
|
47
66
|
const canStart = () => status === STATUS_READY;
|
|
48
67
|
const start = () => {
|
|
49
68
|
if (!canStart()) return;
|
|
50
69
|
status = STATUS_START;
|
|
51
70
|
startAt = Date.now();
|
|
52
|
-
|
|
71
|
+
if (leading === false) dispatcher(execute);
|
|
72
|
+
else execute();
|
|
53
73
|
};
|
|
54
74
|
const canStop = () => status === STATUS_START;
|
|
55
75
|
const stop = () => {
|
|
56
76
|
if (!canStop()) return;
|
|
77
|
+
if (trailing) execute();
|
|
57
78
|
status = STATUS_STOP;
|
|
58
79
|
stopAt = Date.now();
|
|
59
80
|
};
|
|
60
81
|
const canPause = () => status === STATUS_START;
|
|
61
82
|
const pause = () => {
|
|
62
83
|
if (!canPause()) return;
|
|
84
|
+
if (trailing) execute();
|
|
63
85
|
status = STATUS_PAUSE;
|
|
64
86
|
pauseAt = Date.now();
|
|
65
87
|
};
|
|
@@ -84,44 +106,66 @@ function makeInterval(nextTime, effect) {
|
|
|
84
106
|
};
|
|
85
107
|
}
|
|
86
108
|
/**
|
|
87
|
-
*
|
|
109
|
+
* 创建基于 setTimeout 的间隔定时器
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```typescript
|
|
113
|
+
* // 无 condition
|
|
114
|
+
* timerInterval({
|
|
115
|
+
* interval: 1000,
|
|
116
|
+
* runner: (state) => console.log(state.times),
|
|
117
|
+
* })
|
|
118
|
+
*
|
|
119
|
+
* // 有 condition,T 自动推断为 number
|
|
120
|
+
* timerInterval({
|
|
121
|
+
* interval: 1000,
|
|
122
|
+
* condition: (state) => state.times,
|
|
123
|
+
* runner: (state) => state.data.toFixed(2),
|
|
124
|
+
* })
|
|
125
|
+
* ```
|
|
88
126
|
*
|
|
89
|
-
* @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数
|
|
90
|
-
* @param interval - 间隔时间,单位为毫秒
|
|
91
127
|
* @param options - 配置选项
|
|
92
|
-
* @returns
|
|
128
|
+
* @returns 定时器控制方法集合
|
|
93
129
|
*/
|
|
94
|
-
function
|
|
130
|
+
function timerInterval(options) {
|
|
131
|
+
const { runner, interval, condition, leading, trailing } = options;
|
|
95
132
|
let timeId;
|
|
96
|
-
const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval(
|
|
97
|
-
|
|
98
|
-
|
|
133
|
+
const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({
|
|
134
|
+
dispatcher: (dispatch) => {
|
|
135
|
+
timeId = setTimeout(dispatch, interval);
|
|
136
|
+
},
|
|
137
|
+
runner,
|
|
138
|
+
condition,
|
|
139
|
+
leading: leading ?? false,
|
|
140
|
+
trailing
|
|
141
|
+
});
|
|
99
142
|
return {
|
|
100
143
|
start() {
|
|
101
144
|
if (!canStart()) return;
|
|
102
|
-
|
|
103
|
-
else timeId = setTimeout(start, interval);
|
|
145
|
+
start();
|
|
104
146
|
},
|
|
105
147
|
stop() {
|
|
106
148
|
if (!canStop()) return;
|
|
107
|
-
if (options?.trailing) execute();
|
|
108
|
-
clearTimeout(timeId);
|
|
109
149
|
stop();
|
|
150
|
+
clearTimeout(timeId);
|
|
110
151
|
},
|
|
111
152
|
pause() {
|
|
112
153
|
if (!canPause()) return;
|
|
113
|
-
if (options?.trailing) execute();
|
|
114
|
-
clearTimeout(timeId);
|
|
115
154
|
pause();
|
|
155
|
+
clearTimeout(timeId);
|
|
116
156
|
},
|
|
117
157
|
resume(immediate) {
|
|
118
158
|
if (!canResume()) return;
|
|
119
|
-
if (immediate ||
|
|
120
|
-
else timeId = setTimeout(resume, interval);
|
|
159
|
+
if (immediate || leading) resume();
|
|
160
|
+
else timeId = setTimeout(() => resume(), interval);
|
|
161
|
+
},
|
|
162
|
+
execute() {
|
|
163
|
+
clearTimeout(timeId);
|
|
164
|
+
execute();
|
|
121
165
|
}
|
|
122
166
|
};
|
|
123
167
|
}
|
|
124
168
|
//#endregion
|
|
125
|
-
export { makeInterval,
|
|
169
|
+
export { makeInterval, timerInterval };
|
|
126
170
|
|
|
127
171
|
//# sourceMappingURL=timer.mjs.map
|
package/dist/timer.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timer.mjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n *
|
|
1
|
+
{"version":3,"file":"timer.mjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["import type { MaybePromise } from './types';\n\n/**\n * 定时器状态基础接口\n */\nexport type TimerStateBase = {\n /**\n * 执行次数\n */\n times: number;\n /**\n * 开始时间戳\n */\n startAt: number;\n /**\n * 停止时间戳\n */\n stopAt: number;\n /**\n * 暂停时间戳\n */\n pauseAt: number;\n /**\n * 恢复时间戳\n */\n resumeAt: number;\n /**\n * 当前时间戳\n */\n currentAt: number;\n /**\n * 总耗时(包括暂停时间)\n */\n elapsedTime: number;\n /**\n * 实际运行时间(不包括暂停时间)\n */\n runningTime: number;\n /**\n * 当前间隔时间\n */\n intervalTime: number;\n};\n\n/**\n * 定时器状态接口\n * @template T - condition 函数返回值类型,默认为 unknown\n */\nexport type TimerState<T = unknown> = TimerStateBase & {\n /**\n * condition 函数返回值,未传入 condition 时为 null\n */\n data: T;\n};\n\n/**\n * 定时器控制方法集合\n */\nexport type TimerHandler = {\n /**\n * 启动定时器\n */\n start: () => void;\n /**\n * 暂停定时器\n */\n pause: () => void;\n /**\n * 恢复定时器\n * @param immediate - 是否立即执行一次\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止定时器\n */\n stop: () => void;\n /**\n * 清除上一次定时器,立即执行,并开始下一次定时器\n */\n execute: () => void;\n};\n\n/**\n * 间隔定时器控制方法集合,包含状态查询方法\n */\nexport type IntervalHandler = TimerHandler & {\n /**\n * 是否可以启动(处于 READY 状态)\n */\n canStart: () => boolean;\n /**\n * 是否可以停止(处于 START 状态)\n */\n canStop: () => boolean;\n /**\n * 是否可以暂停(处于 START 状态)\n */\n canPause: () => boolean;\n /**\n * 是否可以恢复(处于 PAUSE 状态)\n */\n canResume: () => boolean;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * makeInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type MakeIntervalOptions<T> = {\n /**\n * 调度器函数,用于安排下一次执行\n */\n dispatcher: (dispatch: () => void) => unknown;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 使用 MaybePromise 支持同步或异步条件判断\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * 使用 NoInfer<T> 阻断对该参数的泛型推断,确保 T 仅从 condition 返回值推断\n */\n runner: (timer: TimerState<NoInfer<Awaited<T>>>) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 true\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建可控制的间隔定时器核心函数\n *\n * @example\n * ```typescript\n * // 无 condition,state.data 为 null\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * makeInterval({\n * dispatcher: (dispatch) => setTimeout(dispatch, 1000),\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function makeInterval<T = null>(options: MakeIntervalOptions<T>): IntervalHandler {\n const { dispatcher, runner, condition, leading, trailing } = options;\n let startAt = 0;\n let lastAt = 0;\n let stopAt = 0;\n let pauseAt = 0;\n let resumeAt = 0;\n let times = 0;\n let status = STATUS_READY;\n let runningTime = 0;\n\n const execute = async () => {\n if (status >= STATUS_PAUSE) return;\n\n const now = Date.now();\n const intervalTime = lastAt > 0 ? now - lastAt : 0;\n runningTime += intervalTime;\n lastAt = now;\n const state: TimerState<T> = {\n times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n data: null as T,\n };\n\n if (condition) {\n try {\n state.data = await condition(state);\n } catch {\n dispatcher(execute);\n return;\n }\n }\n\n state.times = ++times;\n\n await (runner as (timer: TimerState<T>) => MaybePromise<unknown>)(state);\n dispatcher(execute);\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n if (leading === false) {\n dispatcher(execute);\n } else {\n execute();\n }\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n if (trailing) execute();\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\n if (trailing) execute();\n status = STATUS_PAUSE;\n pauseAt = Date.now();\n };\n\n const canResume = () => status === STATUS_PAUSE;\n const resume = () => {\n if (!canResume()) return;\n status = STATUS_START;\n resumeAt = Date.now();\n lastAt = resumeAt;\n execute();\n };\n\n return {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n };\n}\n\n/**\n * timerInterval 配置选项\n * @template T - condition 函数返回值类型\n */\nexport type TimerIntervalOptions<T> = {\n /**\n * 间隔时间,单位为毫秒\n */\n interval: number;\n /**\n * 条件函数,每次执行前调用,返回值存入 state.data\n * 抛错时跳过本次 runner 执行,继续下一次调度\n */\n condition?: (state: TimerStateBase) => T;\n /**\n * 执行函数,每次定时器触发时调用,接收完整的定时器状态\n * @param next - 可选的手动触发下一次调度的函数\n */\n runner: (state: TimerState<NoInfer<Awaited<T>>>, next?: () => void) => unknown;\n /**\n * 是否在定时器启动时立即执行一次,默认为 false\n */\n leading?: boolean;\n /**\n * 是否在定时器停止或暂停时额外执行一次(trailing edge)\n */\n trailing?: boolean;\n};\n\n/**\n * 创建基于 setTimeout 的间隔定时器\n *\n * @example\n * ```typescript\n * // 无 condition\n * timerInterval({\n * interval: 1000,\n * runner: (state) => console.log(state.times),\n * })\n *\n * // 有 condition,T 自动推断为 number\n * timerInterval({\n * interval: 1000,\n * condition: (state) => state.times,\n * runner: (state) => state.data.toFixed(2),\n * })\n * ```\n *\n * @param options - 配置选项\n * @returns 定时器控制方法集合\n */\nexport function timerInterval<T = null>(options: TimerIntervalOptions<T>): TimerHandler {\n const { runner, interval, condition, leading, trailing } = options;\n let timeId: number | NodeJS.Timeout;\n const { canStart, canStop, canPause, canResume, start, stop, pause, resume, execute } = makeInterval({\n dispatcher: (dispatch) => {\n timeId = setTimeout(dispatch, interval);\n },\n runner: runner as (timer: TimerState<T>) => MaybePromise<unknown>,\n condition,\n leading: leading ?? false,\n trailing,\n });\n\n return {\n start() {\n if (!canStart()) return;\n start();\n },\n\n stop() {\n if (!canStop()) return;\n stop();\n clearTimeout(timeId);\n },\n\n pause() {\n if (!canPause()) return;\n pause();\n clearTimeout(timeId);\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n if (immediate || leading) {\n resume();\n } else {\n timeId = setTimeout(() => resume(), interval);\n }\n },\n\n execute() {\n clearTimeout(timeId);\n execute();\n },\n };\n}\n"],"mappings":";AAwGA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;AAsDpB,SAAgB,aAAuB,SAAkD;CACvF,MAAM,EAAE,YAAY,QAAQ,WAAW,SAAS,aAAa;CAC7D,IAAI,UAAU;CACd,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,UAAU;CACd,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,cAAc;CAElB,MAAM,UAAU,YAAY;EAC1B,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAuB;GAC3B;GACA;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACA,MAAM;GACP;EAED,IAAI,WACF,IAAI;GACF,MAAM,OAAO,MAAM,UAAU,MAAM;UAC7B;GACN,WAAW,QAAQ;GACnB;;EAIJ,MAAM,QAAQ,EAAE;EAEhB,MAAO,OAA2D,MAAM;EACxE,WAAW,QAAQ;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,SAAS;EACT,UAAU,KAAK,KAAK;EACpB,IAAI,YAAY,OACd,WAAW,QAAQ;OAEnB,SAAS;;CAIb,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,SAAS,EAAE;EAChB,IAAI,UAAU,SAAS;EACvB,SAAS;EACT,SAAS,KAAK,KAAK;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,IAAI,UAAU,SAAS;EACvB,SAAS;EACT,UAAU,KAAK,KAAK;;CAGtB,MAAM,kBAAkB,WAAW;CACnC,MAAM,eAAe;EACnB,IAAI,CAAC,WAAW,EAAE;EAClB,SAAS;EACT,WAAW,KAAK,KAAK;EACrB,SAAS;EACT,SAAS;;CAGX,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACD;;;;;;;;;;;;;;;;;;;;;;;;AAsDH,SAAgB,cAAwB,SAAgD;CACtF,MAAM,EAAE,QAAQ,UAAU,WAAW,SAAS,aAAa;CAC3D,IAAI;CACJ,MAAM,EAAE,UAAU,SAAS,UAAU,WAAW,OAAO,MAAM,OAAO,QAAQ,YAAY,aAAa;EACnG,aAAa,aAAa;GACxB,SAAS,WAAW,UAAU,SAAS;;EAEjC;EACR;EACA,SAAS,WAAW;EACpB;EACD,CAAC;CAEF,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,OAAO;;EAGT,OAAO;GACL,IAAI,CAAC,SAAS,EAAE;GAChB,MAAM;GACN,aAAa,OAAO;;EAGtB,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,OAAO;GACP,aAAa,OAAO;;EAGtB,OAAO,WAAqB;GAC1B,IAAI,CAAC,WAAW,EAAE;GAClB,IAAI,aAAa,SACf,QAAQ;QAER,SAAS,iBAAiB,QAAQ,EAAE,SAAS;;EAIjD,UAAU;GACR,aAAa,OAAO;GACpB,SAAS;;EAEZ"}
|