@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.
Files changed (64) hide show
  1. package/README.md +71 -72
  2. package/dist/array.cjs.map +1 -1
  3. package/dist/array.mjs.map +1 -1
  4. package/dist/async.cjs.map +1 -1
  5. package/dist/async.mjs.map +1 -1
  6. package/dist/cache.cjs.map +1 -1
  7. package/dist/cache.mjs.map +1 -1
  8. package/dist/color.cjs.map +1 -1
  9. package/dist/color.mjs.map +1 -1
  10. package/dist/date.cjs.map +1 -1
  11. package/dist/date.mjs.map +1 -1
  12. package/dist/dict.cjs +1 -1
  13. package/dist/dict.cjs.map +1 -1
  14. package/dist/dict.mjs +1 -1
  15. package/dist/dict.mjs.map +1 -1
  16. package/dist/easing.cjs +1 -2
  17. package/dist/easing.cjs.map +1 -1
  18. package/dist/easing.mjs +1 -2
  19. package/dist/easing.mjs.map +1 -1
  20. package/dist/emitter.cjs.map +1 -1
  21. package/dist/emitter.mjs.map +1 -1
  22. package/dist/env.cjs.map +1 -1
  23. package/dist/env.mjs.map +1 -1
  24. package/dist/error.cjs.map +1 -1
  25. package/dist/error.mjs.map +1 -1
  26. package/dist/exception.cjs.map +1 -1
  27. package/dist/exception.mjs.map +1 -1
  28. package/dist/function.cjs +33 -0
  29. package/dist/function.cjs.map +1 -1
  30. package/dist/function.d.ts +34 -0
  31. package/dist/function.mjs +33 -1
  32. package/dist/function.mjs.map +1 -1
  33. package/dist/index.cjs +1 -1
  34. package/dist/index.mjs +1 -1
  35. package/dist/object/get-set.d.ts +1 -25
  36. package/dist/object.cjs.map +1 -1
  37. package/dist/object.mjs.map +1 -1
  38. package/dist/promise.cjs.map +1 -1
  39. package/dist/promise.mjs.map +1 -1
  40. package/dist/qs.cjs.map +1 -1
  41. package/dist/qs.mjs.map +1 -1
  42. package/dist/regexp.cjs.map +1 -1
  43. package/dist/regexp.mjs.map +1 -1
  44. package/dist/string2.cjs.map +1 -1
  45. package/dist/string2.mjs.map +1 -1
  46. package/dist/time.cjs.map +1 -1
  47. package/dist/time.mjs.map +1 -1
  48. package/dist/timer.cjs +76 -32
  49. package/dist/timer.cjs.map +1 -1
  50. package/dist/timer.d.ts +130 -25
  51. package/dist/timer.mjs +76 -32
  52. package/dist/timer.mjs.map +1 -1
  53. package/dist/tree.cjs.map +1 -1
  54. package/dist/tree.mjs.map +1 -1
  55. package/dist/try.cjs.map +1 -1
  56. package/dist/try.mjs.map +1 -1
  57. package/dist/type.cjs.map +1 -1
  58. package/dist/type.mjs.map +1 -1
  59. package/dist/types.d.ts +1 -1
  60. package/dist/url.cjs +1 -1
  61. package/dist/url.cjs.map +1 -1
  62. package/dist/url.mjs +1 -1
  63. package/dist/url.mjs.map +1 -1
  64. 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
- * @param nextTime - 用于安排下一次执行的函数
11
- * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数
12
- * @returns 返回包含控制方法的对象
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(nextTime, effect) {
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: ++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 (effect.length === 2) effect(state, () => {
41
- nextTime(execute);
42
- });
43
- else {
44
- effect(state);
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
- execute();
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
- * 创建一个基于 `setTimeout` 的间隔定时器
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 {TimerHandler}
129
+ * @returns 定时器控制方法集合
94
130
  */
95
- function timeInterval(callback, interval, options) {
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((call) => {
98
- timeId = setTimeout(call, interval);
99
- }, callback);
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
- if (options?.leading) start();
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 || options?.leading) resume();
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.timeInterval = timeInterval;
171
+ exports.timerInterval = timerInterval;
128
172
 
129
173
  //# sourceMappingURL=timer.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"timer.cjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\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\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\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 = () => {\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 = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\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\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"mappings":";;AA6DA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;AASpB,SAAgB,aACd,UACA,QACA;CACA,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,gBAAgB;EACpB,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAoB;GACxB,OAAO,EAAE;GACT;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACD;EAED,IAAI,OAAO,WAAW,GACpB,OAAO,aAAa;GAClB,SAAS,QAAQ;IACjB;OACG;GACL,OAAO,MAAM;GACb,SAAS,QAAQ;;;CAIrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,SAAS;EACT,UAAU,KAAK,KAAK;EACpB,SAAS;;CAGX,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,SAAS,EAAE;EAChB,SAAS;EACT,SAAS,KAAK,KAAK;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,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;;;;;;;;;;AAsBH,SAAgB,aACd,UACA,UACA,SACc;CACd,IAAI;CACJ,MAAM,EACJ,UACA,SACA,UACA,WACA,OACA,MACA,OACA,QACA,YACE,cAAc,SAAS;EACzB,SAAS,WAAW,MAAM,SAAS;IAClC,SAAS;CAEZ,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GAEjB,IAAI,SAAS,SACX,OAAO;QAEP,SAAS,WAAW,OAAO,SAAS;;EAIxC,OAAO;GACL,IAAI,CAAC,SAAS,EAAE;GAChB,IAAI,SAAS,UAAU,SAAS;GAEhC,aAAa,OAAO;GACpB,MAAM;;EAGR,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,IAAI,SAAS,UAAU,SAAS;GAEhC,aAAa,OAAO;GACpB,OAAO;;EAGT,OAAO,WAAqB;GAC1B,IAAI,CAAC,WAAW,EAAE;GAElB,IAAI,aAAa,SAAS,SACxB,QAAQ;QAER,SAAS,WAAW,QAAQ,SAAS;;EAG1C"}
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 TimerState = {
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 declare function makeInterval(nextTime: (call: () => void) => void, effect: (timer: TimerState, next?: () => void) => unknown): {
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
- export type TimerOptions = {
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
- * 创建一个基于 `setTimeout` 的间隔定时器
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 {TimerHandler}
199
+ * @returns 定时器控制方法集合
95
200
  */
96
- export declare function timeInterval(callback: (state: TimerState, next?: () => void) => unknown, interval: number, options?: TimerOptions): TimerHandler;
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
- * @param nextTime - 用于安排下一次执行的函数
10
- * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数
11
- * @returns 返回包含控制方法的对象
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(nextTime, effect) {
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: ++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 (effect.length === 2) effect(state, () => {
40
- nextTime(execute);
41
- });
42
- else {
43
- effect(state);
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
- execute();
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
- * 创建一个基于 `setTimeout` 的间隔定时器
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 {TimerHandler}
128
+ * @returns 定时器控制方法集合
93
129
  */
94
- function timeInterval(callback, interval, options) {
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((call) => {
97
- timeId = setTimeout(call, interval);
98
- }, callback);
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
- if (options?.leading) start();
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 || options?.leading) resume();
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, timeInterval };
169
+ export { makeInterval, timerInterval };
126
170
 
127
171
  //# sourceMappingURL=timer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"timer.mjs","names":[],"sources":["../src/timer.ts"],"sourcesContent":["/**\n * 定时器状态接口\n */\nexport type TimerState = {\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\nexport type TimerHandler = {\n /**\n * 开始\n */\n start: () => void;\n /**\n * 暂停\n */\n pause: () => void;\n /**\n * 恢复\n */\n resume: (immediate?: boolean) => void;\n /**\n * 停止\n */\n stop: () => void;\n};\n\nconst STATUS_READY = 0;\nconst STATUS_START = 1;\nconst STATUS_PAUSE = 2;\nconst STATUS_STOP = 3;\n\n/**\n * 创建间隔定时器核心函数\n *\n * @param nextTime - 用于安排下一次执行的函数\n * @param effect - 每次执行的回调函数,接收定时器状态和可选的next函数\n * @returns 返回包含控制方法的对象\n */\nexport function makeInterval(\n nextTime: (call: () => void) => void,\n effect: (timer: TimerState, next?: () => void) => unknown,\n) {\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 = () => {\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 = {\n times: ++times,\n startAt,\n stopAt,\n pauseAt,\n resumeAt,\n currentAt: now,\n elapsedTime: startAt > 0 ? now - startAt : 0,\n runningTime,\n intervalTime,\n };\n\n if (effect.length === 2) {\n effect(state, () => {\n nextTime(execute);\n });\n } else {\n effect(state);\n nextTime(execute);\n }\n };\n\n const canStart = () => status === STATUS_READY;\n const start = () => {\n if (!canStart()) return;\n status = STATUS_START;\n startAt = Date.now();\n execute();\n };\n\n const canStop = () => status === STATUS_START;\n const stop = () => {\n if (!canStop()) return;\n status = STATUS_STOP;\n stopAt = Date.now();\n };\n\n const canPause = () => status === STATUS_START;\n const pause = () => {\n if (!canPause()) return;\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\nexport type TimerOptions = {\n /**\n * 是否在定时器开始时立即执行回调\n */\n leading?: boolean;\n /**\n * 是否在定时器停止时执行最后一次回调\n */\n trailing?: boolean;\n};\n\n/**\n * 创建一个基于 `setTimeout` 的间隔定时器\n *\n * @param callback - 每次间隔执行的回调函数,接收定时器状态和可选的 `next` 函数\n * @param interval - 间隔时间,单位为毫秒\n * @param options - 配置选项\n * @returns {TimerHandler}\n */\nexport function timeInterval(\n callback: (state: TimerState, next?: () => void) => unknown,\n interval: number,\n options?: TimerOptions,\n): TimerHandler {\n let timeId: number | NodeJS.Timeout;\n const {\n canStart,\n canStop,\n canPause,\n canResume,\n start,\n stop,\n pause,\n resume,\n execute,\n } = makeInterval((call) => {\n timeId = setTimeout(call, interval);\n }, callback);\n\n return {\n start() {\n if (!canStart()) return;\n\n if (options?.leading) {\n start();\n } else {\n timeId = setTimeout(start, interval);\n }\n },\n\n stop() {\n if (!canStop()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n stop();\n },\n\n pause() {\n if (!canPause()) return;\n if (options?.trailing) execute();\n\n clearTimeout(timeId);\n pause();\n },\n\n resume(immediate?: boolean) {\n if (!canResume()) return;\n\n if (immediate || options?.leading) {\n resume();\n } else {\n timeId = setTimeout(resume, interval);\n }\n },\n };\n}\n"],"mappings":";AA6DA,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,eAAe;AACrB,IAAM,cAAc;;;;;;;;AASpB,SAAgB,aACd,UACA,QACA;CACA,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,gBAAgB;EACpB,IAAI,UAAU,cAAc;EAE5B,MAAM,MAAM,KAAK,KAAK;EACtB,MAAM,eAAe,SAAS,IAAI,MAAM,SAAS;EACjD,eAAe;EACf,SAAS;EACT,MAAM,QAAoB;GACxB,OAAO,EAAE;GACT;GACA;GACA;GACA;GACA,WAAW;GACX,aAAa,UAAU,IAAI,MAAM,UAAU;GAC3C;GACA;GACD;EAED,IAAI,OAAO,WAAW,GACpB,OAAO,aAAa;GAClB,SAAS,QAAQ;IACjB;OACG;GACL,OAAO,MAAM;GACb,SAAS,QAAQ;;;CAIrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,SAAS;EACT,UAAU,KAAK,KAAK;EACpB,SAAS;;CAGX,MAAM,gBAAgB,WAAW;CACjC,MAAM,aAAa;EACjB,IAAI,CAAC,SAAS,EAAE;EAChB,SAAS;EACT,SAAS,KAAK,KAAK;;CAGrB,MAAM,iBAAiB,WAAW;CAClC,MAAM,cAAc;EAClB,IAAI,CAAC,UAAU,EAAE;EACjB,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;;;;;;;;;;AAsBH,SAAgB,aACd,UACA,UACA,SACc;CACd,IAAI;CACJ,MAAM,EACJ,UACA,SACA,UACA,WACA,OACA,MACA,OACA,QACA,YACE,cAAc,SAAS;EACzB,SAAS,WAAW,MAAM,SAAS;IAClC,SAAS;CAEZ,OAAO;EACL,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GAEjB,IAAI,SAAS,SACX,OAAO;QAEP,SAAS,WAAW,OAAO,SAAS;;EAIxC,OAAO;GACL,IAAI,CAAC,SAAS,EAAE;GAChB,IAAI,SAAS,UAAU,SAAS;GAEhC,aAAa,OAAO;GACpB,MAAM;;EAGR,QAAQ;GACN,IAAI,CAAC,UAAU,EAAE;GACjB,IAAI,SAAS,UAAU,SAAS;GAEhC,aAAa,OAAO;GACpB,OAAO;;EAGT,OAAO,WAAqB;GAC1B,IAAI,CAAC,WAAW,EAAE;GAElB,IAAI,aAAa,SAAS,SACxB,QAAQ;QAER,SAAS,WAAW,QAAQ,SAAS;;EAG1C"}
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"}