keytask-core 1.0.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/LICENSE +21 -0
- package/README.md +409 -0
- package/dist/cjs/index.cjs +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/types/helpers/getNow.d.ts +2 -0
- package/dist/types/helpers/taskManager.d.ts +105 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/types/types.d.ts +195 -0
- package/package.json +41 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Georg Schilin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<h2></h2>
|
|
4
|
+
|
|
5
|
+
### Table of contents
|
|
6
|
+
|
|
7
|
+
- [About](#about)
|
|
8
|
+
- [Installation](#installation)
|
|
9
|
+
- [API](#api)
|
|
10
|
+
- [Common patterns](#common-patterns)
|
|
11
|
+
- [License](#license)
|
|
12
|
+
|
|
13
|
+
<h2></h2>
|
|
14
|
+
|
|
15
|
+
### About
|
|
16
|
+
|
|
17
|
+
`keytask` is a tiny TypeScript library for key-based control of timing-sensitive work.
|
|
18
|
+
|
|
19
|
+
It is designed for render-heavy UI, scroll libraries, animation systems and games: places where you need to schedule, replace, lock, loop and cancel work without scattering raw `setTimeout`, `requestAnimationFrame` and cleanup state across the codebase.
|
|
20
|
+
|
|
21
|
+
It is not an animation engine. It does not provide easing, tweens, timelines, physics or rendering. It only controls when work is allowed to run.
|
|
22
|
+
|
|
23
|
+
The core idea is simple - the same task key always describes the same unit of work.
|
|
24
|
+
|
|
25
|
+
<h2></h2>
|
|
26
|
+
|
|
27
|
+
### Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install keytask-core
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { setTask } from "keytask-core";
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> **✦ Note:**
|
|
38
|
+
>
|
|
39
|
+
> - Supports both **ESM** (`import`) and **CommonJS** (`require`) builds.
|
|
40
|
+
> - Supports one shared global manager and isolated local managers.
|
|
41
|
+
> - Written in TypeScript and ships declaration files.
|
|
42
|
+
> - No runtime dependencies.
|
|
43
|
+
> - RAF mode uses `requestAnimationFrame` / `cancelAnimationFrame` when available and falls back to `setTimeout(..., 16)` with a console warning when those APIs are missing.
|
|
44
|
+
|
|
45
|
+
<h2></h2>
|
|
46
|
+
|
|
47
|
+
### API
|
|
48
|
+
|
|
49
|
+
<ul><div>
|
|
50
|
+
|
|
51
|
+
###### **— GLOBAL —**
|
|
52
|
+
|
|
53
|
+
<details><summary><b><code>setTask</code></b>: <em>schedule latest one-shot work by timeout or RAF</em></summary><br /><ul><div>
|
|
54
|
+
|
|
55
|
+
<b>Usage:</b><br />
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
setTask(callback, timer, key?);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- `callback` - work to run once.
|
|
62
|
+
- `timer` - timeout in milliseconds or `"raf"`.
|
|
63
|
+
- `key` - optional string key, reusing the same key replaces the previous task state.
|
|
64
|
+
|
|
65
|
+
<br />
|
|
66
|
+
|
|
67
|
+
<b>Description:</b><em><br />
|
|
68
|
+
Schedules one task and returns its key.<br />
|
|
69
|
+
This is useful for "latest wins" work: scroll-end handlers, delayed cleanup, render batching, or any task where only the newest pending callback should survive.<br />
|
|
70
|
+
✦ A single key can only reference one active task within the same manager instance.
|
|
71
|
+
</em><br />
|
|
72
|
+
|
|
73
|
+
<b>Return:</b><br />
|
|
74
|
+
Returns the passed key, or an automatically generated key when `key` is omitted.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
const key = setTask(callback, "raf");
|
|
78
|
+
|
|
79
|
+
cancelTask(key);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
<b>Example:</b>
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
setTask(
|
|
86
|
+
() => {
|
|
87
|
+
doSomething();
|
|
88
|
+
},
|
|
89
|
+
"raf",
|
|
90
|
+
"my-key",
|
|
91
|
+
);
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
</div></ul></details>
|
|
95
|
+
|
|
96
|
+
<h2></h2>
|
|
97
|
+
|
|
98
|
+
<details><summary><b><code>setLockTask</code></b>: <em>run now, then lock repeated calls</em></summary><br /><ul><div>
|
|
99
|
+
|
|
100
|
+
<b>Usage:</b><br />
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
setLockTask(callback, timer, key?);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
- `callback` - work to run immediately.
|
|
107
|
+
- `timer` - lock duration in milliseconds or `"raf"` for a frame lock.
|
|
108
|
+
- `key` - optional string key, calls are ignored while the key already belongs to any task state.
|
|
109
|
+
|
|
110
|
+
<br />
|
|
111
|
+
|
|
112
|
+
<b>Description:</b><em><br />
|
|
113
|
+
Runs the callback immediately, then blocks repeated calls with the same key until the timeout ends or the next RAF unlocks it.<br />
|
|
114
|
+
This is useful for "first wins" work: frame locks, cooldowns, input guards, or preventing repeated calls from doing too much work in the same frame/window.<br />
|
|
115
|
+
✦ A single key can only reference one active task within the same manager instance.
|
|
116
|
+
</em><br />
|
|
117
|
+
|
|
118
|
+
<b>Return:</b><br />
|
|
119
|
+
Returns the passed key, or an automatically generated key when `key` is omitted.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
const key = setLockTask(callback, "raf");
|
|
123
|
+
|
|
124
|
+
cancelTask(key);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
<b>Example:</b>
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
setLockTask(
|
|
131
|
+
() => {
|
|
132
|
+
doSomething();
|
|
133
|
+
},
|
|
134
|
+
"raf",
|
|
135
|
+
"my-key",
|
|
136
|
+
);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
</div></ul></details>
|
|
140
|
+
|
|
141
|
+
<h2></h2>
|
|
142
|
+
|
|
143
|
+
<details><summary><b><code>setThrottleTask</code></b>: <em>run now, then keep the latest repeated call while throttled</em></summary><br /><ul><div>
|
|
144
|
+
|
|
145
|
+
<b>Usage:</b><br />
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
setThrottleTask(callback, timer, key?);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- `callback` - work to run immediately, or save as the latest trailing call while throttled.
|
|
152
|
+
- `timer` - throttle window in milliseconds or `"raf"` for a frame throttle.
|
|
153
|
+
- `key` - optional string key, repeated calls with the same key keep only the latest trailing callback.
|
|
154
|
+
|
|
155
|
+
<br />
|
|
156
|
+
|
|
157
|
+
<b>Description:</b><em><br />
|
|
158
|
+
Runs the first callback immediately. While the key is throttled, repeated calls do not run immediately. Instead, only the latest callback is saved and runs when the throttle window opens again.<br />
|
|
159
|
+
This is useful for "first now, latest later" work: pointer updates, resize updates, scroll sync, render requests or other cases where dropping the final update would be incorrect.<br />
|
|
160
|
+
✦ A single key can only reference one active task within the same manager instance.
|
|
161
|
+
</em><br />
|
|
162
|
+
|
|
163
|
+
<b>Return:</b><br />
|
|
164
|
+
Returns the passed key, or an automatically generated key when `key` is omitted.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
const key = setThrottleTask(callback, "raf");
|
|
168
|
+
|
|
169
|
+
cancelTask(key);
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
<b>Example:</b>
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
setThrottleTask(
|
|
176
|
+
() => {
|
|
177
|
+
doSomething();
|
|
178
|
+
},
|
|
179
|
+
"raf",
|
|
180
|
+
"my-key",
|
|
181
|
+
);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
</div></ul></details>
|
|
185
|
+
|
|
186
|
+
<h2></h2>
|
|
187
|
+
|
|
188
|
+
<details><summary><b><code>setLoopTask</code></b>: <em>run repeated work by timeout or RAF</em></summary><br /><ul><div>
|
|
189
|
+
|
|
190
|
+
<b>Usage:</b><br />
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
setLoopTask(callback, timer, key?);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
- `callback` - repeated work. Receives `tick`, `time`, and `delta`.
|
|
197
|
+
- `timer` - interval in milliseconds or `"raf"` for an animation-frame loop.
|
|
198
|
+
- `key` - optional string key, reusing the same key replaces the previous task state.
|
|
199
|
+
|
|
200
|
+
<br />
|
|
201
|
+
|
|
202
|
+
<b>Description:</b><em><br />
|
|
203
|
+
Starts repeated work and returns its key.<br />
|
|
204
|
+
The callback receives a 1-based tick count, current time and delta since the previous tick. Return <code>false</code> to stop the loop.<br />
|
|
205
|
+
✦ A single key can only reference one active task within the same manager instance.
|
|
206
|
+
</em><br />
|
|
207
|
+
|
|
208
|
+
<b>Return:</b><br />
|
|
209
|
+
Returns the passed key, or an automatically generated key when `key` is omitted.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const key = setLoopTask(callback, "raf");
|
|
213
|
+
|
|
214
|
+
cancelTask(key);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
<b>Example:</b>
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
setLoopTask(
|
|
221
|
+
(tick, time, delta) => {
|
|
222
|
+
doSomething();
|
|
223
|
+
|
|
224
|
+
if (tick > 10) return false; // exit
|
|
225
|
+
},
|
|
226
|
+
"raf",
|
|
227
|
+
"my-key",
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
</div></ul></details>
|
|
232
|
+
|
|
233
|
+
<h2></h2>
|
|
234
|
+
|
|
235
|
+
<details><summary><b><code>cancelTask</code></b>: <em>cancel tasks</em></summary><br /><ul><div>
|
|
236
|
+
|
|
237
|
+
<b>Usage:</b><br />
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
cancelTask("key");
|
|
241
|
+
cancelTask(["key1", "key2"]);
|
|
242
|
+
cancelTask(); // clear all tasks
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
<b>Description:</b><em><br />
|
|
246
|
+
Cancels one, several, or all tasks in the global manager.
|
|
247
|
+
</em><br />
|
|
248
|
+
|
|
249
|
+
</div></ul></details>
|
|
250
|
+
|
|
251
|
+
<h2></h2>
|
|
252
|
+
|
|
253
|
+
<details><summary><b><code>hasTask</code></b>: <em>check tasks</em></summary><br /><ul><div>
|
|
254
|
+
|
|
255
|
+
<b>Usage:</b><br />
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
hasTask("key");
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
<b>Description:</b><em><br />
|
|
262
|
+
Check pending tasks, active locks, active throttles or active loops.<br />
|
|
263
|
+
Returns <code>true</code> when the key belongs to any active task state in the global manager.
|
|
264
|
+
</em><br />
|
|
265
|
+
|
|
266
|
+
<b>Example:</b>
|
|
267
|
+
|
|
268
|
+
```ts
|
|
269
|
+
if (hasTask("render")) {
|
|
270
|
+
cancelTask("render");
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
</div></ul></details>
|
|
275
|
+
|
|
276
|
+
<h2></h2>
|
|
277
|
+
|
|
278
|
+
###### **— LOCAL —**
|
|
279
|
+
|
|
280
|
+
<details><summary><b><code>createTaskManager</code></b>: <em>create isolated task state</em></summary><br /><ul><div>
|
|
281
|
+
|
|
282
|
+
<b>Usage:</b><br />
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
const tasks = createTaskManager();
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
The returned manager has the same task methods as the global API, plus `clear()`.
|
|
289
|
+
|
|
290
|
+
<b>Description:</b><em><br />
|
|
291
|
+
Creates a local manager with its own one-shot tasks, locks, throttles and loops.<br />
|
|
292
|
+
Use it for components, scenes, entities or modules that need isolated cleanup. Calling <code>clear()</code> cancels everything inside that local manager without touching the global manager.
|
|
293
|
+
</em>
|
|
294
|
+
|
|
295
|
+
<b>Example:</b>
|
|
296
|
+
|
|
297
|
+
```ts
|
|
298
|
+
const sceneTasks = createTaskManager();
|
|
299
|
+
|
|
300
|
+
sceneTasks.setLoopTask(callback, "raf", "my-raf-key");
|
|
301
|
+
sceneTasks.setTask(callback, 1000, "my-timeout-key");
|
|
302
|
+
|
|
303
|
+
function destroyScene() {
|
|
304
|
+
sceneTasks.clear();
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
</div></ul></details>
|
|
309
|
+
|
|
310
|
+
<h2></h2>
|
|
311
|
+
|
|
312
|
+
</div></ul>
|
|
313
|
+
|
|
314
|
+
<h2></h2>
|
|
315
|
+
|
|
316
|
+
### Common patterns
|
|
317
|
+
|
|
318
|
+
<details><summary><b>Render batching</b>: <em>keep only the latest render request for the next frame</em></summary><br />
|
|
319
|
+
|
|
320
|
+
```ts
|
|
321
|
+
setTask(
|
|
322
|
+
() => {
|
|
323
|
+
render();
|
|
324
|
+
},
|
|
325
|
+
"raf",
|
|
326
|
+
"render",
|
|
327
|
+
);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
</details>
|
|
331
|
+
|
|
332
|
+
<details><summary><b>Debounced work</b>: <em>reuse the same key so only the latest delayed callback runs</em></summary><br />
|
|
333
|
+
|
|
334
|
+
```ts
|
|
335
|
+
setTask(
|
|
336
|
+
() => {
|
|
337
|
+
saveDraft();
|
|
338
|
+
},
|
|
339
|
+
300,
|
|
340
|
+
"save-draft",
|
|
341
|
+
);
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
</details>
|
|
345
|
+
|
|
346
|
+
<details><summary><b>Input cooldown</b>: <em>run once, then ignore repeated calls while locked</em></summary><br />
|
|
347
|
+
|
|
348
|
+
```ts
|
|
349
|
+
setLockTask(
|
|
350
|
+
() => {
|
|
351
|
+
submitInput();
|
|
352
|
+
},
|
|
353
|
+
150,
|
|
354
|
+
"input",
|
|
355
|
+
);
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
</details>
|
|
359
|
+
|
|
360
|
+
<details><summary><b>Latest trailing update</b>: <em>run now, then preserve the latest update during the throttle window</em></summary><br />
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
setThrottleTask(
|
|
364
|
+
() => {
|
|
365
|
+
syncPointerState();
|
|
366
|
+
},
|
|
367
|
+
"raf",
|
|
368
|
+
"pointer",
|
|
369
|
+
);
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
</details>
|
|
373
|
+
|
|
374
|
+
<details><summary><b>Animation loop</b>: <em>run repeated work until the callback stops it</em></summary><br />
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
setLoopTask(
|
|
378
|
+
(tick, time, delta) => {
|
|
379
|
+
update(delta);
|
|
380
|
+
|
|
381
|
+
if (tick > 10) return false;
|
|
382
|
+
},
|
|
383
|
+
"raf",
|
|
384
|
+
"loop",
|
|
385
|
+
);
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
</details>
|
|
389
|
+
|
|
390
|
+
<details><summary><b>Local cleanup</b>: <em>isolate task state and clear it on teardown</em></summary><br />
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
const tasks = createTaskManager();
|
|
394
|
+
|
|
395
|
+
tasks.setLoopTask(updateScene, "raf", "loop");
|
|
396
|
+
tasks.setTask(removeHint, 1000, "hint");
|
|
397
|
+
|
|
398
|
+
function destroy() {
|
|
399
|
+
tasks.clear();
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
</details>
|
|
404
|
+
|
|
405
|
+
<h2></h2>
|
|
406
|
+
|
|
407
|
+
### License
|
|
408
|
+
|
|
409
|
+
- [MIT](./LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=()=>"undefined"!=typeof performance&&performance.now?performance.now():Date.now();let t=0,a=!1;const n=()=>"key_"+t++,r=()=>"function"!=typeof globalThis.requestAnimationFrame||"function"!=typeof globalThis.cancelAnimationFrame?(a||(a=!0),{requestAnimationFrame:t=>globalThis.setTimeout(()=>t(e()),16),cancelAnimationFrame:e=>globalThis.clearTimeout(e)}):{requestAnimationFrame:e=>globalThis.requestAnimationFrame(e),cancelAnimationFrame:e=>globalThis.cancelAnimationFrame(e)};function l(){const t=[],a=new Map,l=new Map,i=new Map,s=new Set,o=new Map,c=new Map;let m=null,u=null;const d=()=>{null!==m&&(clearTimeout(m),m=null)},f=()=>{null!==u&&(r().cancelAnimationFrame(u),u=null)},k=()=>{if(d(),0===t.length)return;const a=t[0],n=Math.max(0,a.runAt-e());m=setTimeout(()=>{m=null;const a=e(),n=[];for(;t.length&&t[0].runAt<=a;){const e=t.shift();s.has(e.key)||n.push(e)}n.forEach(e=>{s.add(e.key);try{e.callback()}finally{s.delete(e.key)}}),k()},n)},h=e=>{const t=l.get(e);t&&(null!==t.timerId&&("raf"===t.timer?r().cancelAnimationFrame(t.timerId):clearTimeout(t.timerId)),l.delete(e))},T=(e,t)=>{const a=l.get(e);if(!a||s.has(e))return;a.timerId=null,a.tick+=1;const n=(a.tick,t-a.lastTime);let r;a.lastTime=t,s.add(e);try{r=a.callback(a.tick,t,n)}finally{s.delete(e)}!1!==r&&l.has(e)?y(a):l.delete(e)},y=t=>{if(!l.has(t.key))return;if("raf"===t.timer)return void(t.timerId=r().requestAnimationFrame(e=>T(t.key,e)));const a=Math.max(0,t.timer);t.timerId=setTimeout(()=>T(t.key,e()),a)},A=(e,t)=>{s.add(e);try{t()}finally{s.delete(e)}},p=e=>{const t=i.get(e);if(!t)return;t.timerId=null;const a=t.trailing;t.trailing=null,a?(A(e,a),i.has(e)&&g(t)):i.delete(e)},g=e=>{if(!i.has(e.key))return;if("raf"===e.timer)return void(e.timerId=r().requestAnimationFrame(()=>p(e.key)));const t=Math.max(0,e.timer);e.timerId=setTimeout(()=>p(e.key),t)},F=e=>{const t=i.get(e);t&&(null!==t.timerId&&("raf"===t.timer?r().cancelAnimationFrame(t.timerId):clearTimeout(t.timerId)),i.delete(e))},I=()=>{d(),f(),t.splice(0,t.length),a.clear(),s.clear(),o.forEach(e=>clearTimeout(e)),o.clear(),c.forEach(e=>r().cancelAnimationFrame(e)),c.clear(),Array.from(l.keys()).forEach(h),Array.from(i.keys()).forEach(F)},x=e=>s.has(e)||o.has(e)||c.has(e)||a.has(e)||l.has(e)||i.has(e)||t.some(t=>t.key===e),M=e=>{s.delete(e);const n=o.get(e);void 0!==n&&(clearTimeout(n),o.delete(e));const l=c.get(e);void 0!==l&&(r().cancelAnimationFrame(l),c.delete(e)),(e=>{a.delete(e),0===a.size&&f();const n=t.filter(t=>t.key!==e);t.splice(0,t.length,...n)})(e),h(e),F(e)};return{setTask:(l,i,o)=>{const c=(null!=o?o:n())+"";if(void 0!==o&&M(c),"raf"===i)return a.set(c,l),null===u&&(u=r().requestAnimationFrame(()=>{u=null;const e=Array.from(a.entries());a.clear(),e.forEach(([e,t])=>{if(!s.has(e)){s.add(e);try{t()}finally{s.delete(e)}}})})),c;const m=Math.max(0,i),d={key:c,runAt:e()+m,callback:l};return function(e,t){let a=0,n=e.length;for(;n>a;){const r=a+n>>1;e[r].runAt<t.runAt?a=r+1:n=r}e.splice(a,0,t)}(t,d),k(),c},setLockTask:(e,t,a)=>{const l=(null!=a?a:n())+"";if(x(l))return l;s.add(l);try{e()}finally{if("raf"===t){const e=r().requestAnimationFrame(()=>{s.delete(l),c.delete(l)});c.set(l,e)}else{const e=setTimeout(()=>{s.delete(l),o.delete(l)},Math.max(0,t));o.set(l,e)}}return l},setThrottleTask:(e,t,a)=>{const r=(null!=a?a:n())+"",l=i.get(r);if(l)return l.trailing=e,r;void 0!==a&&M(r);const s={key:r,timer:t,trailing:null,timerId:null};return i.set(r,s),A(r,e),i.has(r)&&g(s),r},setLoopTask:(t,a,r)=>{const i=(null!=r?r:n())+"";void 0!==r&&M(i);const s={key:i,callback:t,timer:a,tick:0,lastTime:e(),timerId:null};return l.set(i,s),y(s),i},cancelTask:e=>{void 0!==e?((Array.isArray(e)?e:[e]).forEach(e=>M(e+"")),k()):I()},hasTask:e=>x(e+""),clear:I}}const i=l(),s=i.setTask,o=i.setLockTask,c=i.setThrottleTask,m=i.setLoopTask,u=i.cancelTask,d=i.hasTask;exports.cancelTask=u,exports.createTaskManager=l,exports.hasTask=d,exports.setLockTask=o,exports.setLoopTask=m,exports.setTask=s,exports.setThrottleTask=c;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=()=>"undefined"!=typeof performance&&performance.now?performance.now():Date.now();let t=0,a=!1;const n=()=>"key_"+t++,r=()=>"function"!=typeof globalThis.requestAnimationFrame||"function"!=typeof globalThis.cancelAnimationFrame?(a||(a=!0),{requestAnimationFrame:t=>globalThis.setTimeout(()=>t(e()),16),cancelAnimationFrame:e=>globalThis.clearTimeout(e)}):{requestAnimationFrame:e=>globalThis.requestAnimationFrame(e),cancelAnimationFrame:e=>globalThis.cancelAnimationFrame(e)};function l(){const t=[],a=new Map,l=new Map,i=new Map,o=new Set,s=new Map,c=new Map;let m=null,u=null;const d=()=>{null!==m&&(clearTimeout(m),m=null)},f=()=>{null!==u&&(r().cancelAnimationFrame(u),u=null)},h=()=>{if(d(),0===t.length)return;const a=t[0],n=Math.max(0,a.runAt-e());m=setTimeout(()=>{m=null;const a=e(),n=[];for(;t.length&&t[0].runAt<=a;){const e=t.shift();o.has(e.key)||n.push(e)}n.forEach(e=>{o.add(e.key);try{e.callback()}finally{o.delete(e.key)}}),h()},n)},k=e=>{const t=l.get(e);t&&(null!==t.timerId&&("raf"===t.timer?r().cancelAnimationFrame(t.timerId):clearTimeout(t.timerId)),l.delete(e))},y=(e,t)=>{const a=l.get(e);if(!a||o.has(e))return;a.timerId=null,a.tick+=1;const n=(a.tick,t-a.lastTime);let r;a.lastTime=t,o.add(e);try{r=a.callback(a.tick,t,n)}finally{o.delete(e)}!1!==r&&l.has(e)?T(a):l.delete(e)},T=t=>{if(!l.has(t.key))return;if("raf"===t.timer)return void(t.timerId=r().requestAnimationFrame(e=>y(t.key,e)));const a=Math.max(0,t.timer);t.timerId=setTimeout(()=>y(t.key,e()),a)},A=(e,t)=>{o.add(e);try{t()}finally{o.delete(e)}},g=e=>{const t=i.get(e);if(!t)return;t.timerId=null;const a=t.trailing;t.trailing=null,a?(A(e,a),i.has(e)&&p(t)):i.delete(e)},p=e=>{if(!i.has(e.key))return;if("raf"===e.timer)return void(e.timerId=r().requestAnimationFrame(()=>g(e.key)));const t=Math.max(0,e.timer);e.timerId=setTimeout(()=>g(e.key),t)},F=e=>{const t=i.get(e);t&&(null!==t.timerId&&("raf"===t.timer?r().cancelAnimationFrame(t.timerId):clearTimeout(t.timerId)),i.delete(e))},I=()=>{d(),f(),t.splice(0,t.length),a.clear(),o.clear(),s.forEach(e=>clearTimeout(e)),s.clear(),c.forEach(e=>r().cancelAnimationFrame(e)),c.clear(),Array.from(l.keys()).forEach(k),Array.from(i.keys()).forEach(F)},b=e=>o.has(e)||s.has(e)||c.has(e)||a.has(e)||l.has(e)||i.has(e)||t.some(t=>t.key===e),M=e=>{o.delete(e);const n=s.get(e);void 0!==n&&(clearTimeout(n),s.delete(e));const l=c.get(e);void 0!==l&&(r().cancelAnimationFrame(l),c.delete(e)),(e=>{a.delete(e),0===a.size&&f();const n=t.filter(t=>t.key!==e);t.splice(0,t.length,...n)})(e),k(e),F(e)};return{setTask:(l,i,s)=>{const c=(null!=s?s:n())+"";if(void 0!==s&&M(c),"raf"===i)return a.set(c,l),null===u&&(u=r().requestAnimationFrame(()=>{u=null;const e=Array.from(a.entries());a.clear(),e.forEach(([e,t])=>{if(!o.has(e)){o.add(e);try{t()}finally{o.delete(e)}}})})),c;const m=Math.max(0,i),d={key:c,runAt:e()+m,callback:l};return function(e,t){let a=0,n=e.length;for(;n>a;){const r=a+n>>1;e[r].runAt<t.runAt?a=r+1:n=r}e.splice(a,0,t)}(t,d),h(),c},setLockTask:(e,t,a)=>{const l=(null!=a?a:n())+"";if(b(l))return l;o.add(l);try{e()}finally{if("raf"===t){const e=r().requestAnimationFrame(()=>{o.delete(l),c.delete(l)});c.set(l,e)}else{const e=setTimeout(()=>{o.delete(l),s.delete(l)},Math.max(0,t));s.set(l,e)}}return l},setThrottleTask:(e,t,a)=>{const r=(null!=a?a:n())+"",l=i.get(r);if(l)return l.trailing=e,r;void 0!==a&&M(r);const o={key:r,timer:t,trailing:null,timerId:null};return i.set(r,o),A(r,e),i.has(r)&&p(o),r},setLoopTask:(t,a,r)=>{const i=(null!=r?r:n())+"";void 0!==r&&M(i);const o={key:i,callback:t,timer:a,tick:0,lastTime:e(),timerId:null};return l.set(i,o),T(o),i},cancelTask:e=>{void 0!==e?((Array.isArray(e)?e:[e]).forEach(e=>M(e+"")),h()):I()},hasTask:e=>b(e+""),clear:I}}const i=l(),o=i.setTask,s=i.setLockTask,c=i.setThrottleTask,m=i.setLoopTask,u=i.cancelTask,d=i.hasTask;export{u as cancelTask,l as createTaskManager,d as hasTask,s as setLockTask,m as setLoopTask,o as setTask,c as setThrottleTask};
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { CancelTaskData, LoopTaskCallback, TaskCallback, TaskKey, TaskManager, TaskTimer } from "../types/types";
|
|
2
|
+
/**---
|
|
3
|
+
* ## 
|
|
4
|
+
* ### ***createTaskManager***:
|
|
5
|
+
* create isolated task state.
|
|
6
|
+
* @description
|
|
7
|
+
* Use it for components, scenes, entities or modules that need independent cleanup.
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const tasks = createTaskManager();
|
|
11
|
+
*
|
|
12
|
+
* tasks.setLoopTask(callback, "raf", "my-raf-key");
|
|
13
|
+
* tasks.setTask(callback, 1000, "my-timeout-key");
|
|
14
|
+
*
|
|
15
|
+
* tasks.clear();
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
declare function createTaskManager(): TaskManager;
|
|
19
|
+
/**---
|
|
20
|
+
* ## 
|
|
21
|
+
* ### ***setTask***:
|
|
22
|
+
* schedule latest one-shot work by timeout or RAF.
|
|
23
|
+
* @description
|
|
24
|
+
* If the same `key` is used again, the previous task state is replaced.
|
|
25
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* setTask(() => {
|
|
29
|
+
* doSomething();
|
|
30
|
+
* }, "raf", "my-key");
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
declare const setTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
34
|
+
/**---
|
|
35
|
+
* ## 
|
|
36
|
+
* ### ***setLockTask***:
|
|
37
|
+
* run work immediately, then lock repeated calls by key.
|
|
38
|
+
* @description
|
|
39
|
+
* The first call wins. Calls with a key that already belongs to a task state are ignored until that key becomes free.
|
|
40
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* setLockTask(() => {
|
|
44
|
+
* doSomething();
|
|
45
|
+
* }, "raf", "my-key");
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
declare const setLockTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
49
|
+
/**---
|
|
50
|
+
* ## 
|
|
51
|
+
* ### ***setThrottleTask***:
|
|
52
|
+
* run work immediately, then keep the latest repeated call while throttled.
|
|
53
|
+
* @description
|
|
54
|
+
* The first call runs immediately. Calls with the same `key` during the throttle window save only the latest callback, which runs when the window opens again.
|
|
55
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* setThrottleTask(() => {
|
|
59
|
+
* doSomething();
|
|
60
|
+
* }, "raf", "my-key");
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
declare const setThrottleTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
64
|
+
/**---
|
|
65
|
+
* ## 
|
|
66
|
+
* ### ***setLoopTask***:
|
|
67
|
+
* run repeated work by timeout or RAF.
|
|
68
|
+
* @description
|
|
69
|
+
* If the same `key` is used again, the previous task state is cancelled and replaced. Return `false` from callback to stop the loop.
|
|
70
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
71
|
+
* @example
|
|
72
|
+
* ```ts
|
|
73
|
+
* setLoopTask((tick, time, delta) => {
|
|
74
|
+
* doSomething();
|
|
75
|
+
*
|
|
76
|
+
* if (tick > 10) return false;
|
|
77
|
+
* }, "raf", "my-key");
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
declare const setLoopTask: (callback: LoopTaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
81
|
+
/**---
|
|
82
|
+
* ## 
|
|
83
|
+
* ### ***cancelTask***:
|
|
84
|
+
* cancel one task, several tasks or all tasks in the global manager.
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* cancelTask("my-key");
|
|
88
|
+
* cancelTask(["key1", "key2"]);
|
|
89
|
+
* cancelTask();
|
|
90
|
+
* ```
|
|
91
|
+
*/
|
|
92
|
+
declare const cancelTask: (taskData?: CancelTaskData) => void;
|
|
93
|
+
/**---
|
|
94
|
+
* ## 
|
|
95
|
+
* ### ***hasTask***:
|
|
96
|
+
* check whether a key belongs to any active task state.
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* if (hasTask("my-key")) {
|
|
100
|
+
* cancelTask("my-key");
|
|
101
|
+
* }
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
declare const hasTask: (key: TaskKey) => boolean;
|
|
105
|
+
export { cancelTask, createTaskManager, hasTask, setLockTask, setLoopTask, setTask, setThrottleTask, };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**---
|
|
2
|
+
* ## 
|
|
3
|
+
* ### ***TaskKey***:
|
|
4
|
+
* shared task key used by `setTask`, `setLockTask`, `setThrottleTask`, `setLoopTask`, `cancelTask` and `hasTask`.
|
|
5
|
+
* @description
|
|
6
|
+
* `TaskKey` is intentionally a string. One key can belong to only one active task state inside a manager. Readable keys make scheduling calls easier to scan, especially when `timer` can be a number.
|
|
7
|
+
* @example
|
|
8
|
+
* ```ts
|
|
9
|
+
* setTask(callback, "raf", "my-key");
|
|
10
|
+
* setThrottleTask(callback, 150, "my-key");
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
type TaskKey = string;
|
|
14
|
+
/**---
|
|
15
|
+
* ## 
|
|
16
|
+
* ### ***TaskTimer***:
|
|
17
|
+
* scheduler used by task primitives.
|
|
18
|
+
* @description
|
|
19
|
+
* - `number`: *timeout delay in milliseconds*
|
|
20
|
+
* - `"raf"`: *run on `requestAnimationFrame`*
|
|
21
|
+
* @note
|
|
22
|
+
* `0` is a real `setTimeout(..., 0)` delay. Use `"raf"` explicitly for frame scheduling. RAF mode uses `requestAnimationFrame` / `cancelAnimationFrame` when available and falls back to `setTimeout(..., 16)` with a console warning when those APIs are missing.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* setTask(callback, 300, "my-key");
|
|
26
|
+
* setTask(callback, "raf", "my-key");
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
type TaskTimer = number | "raf";
|
|
30
|
+
/**---
|
|
31
|
+
* ## 
|
|
32
|
+
* ### ***TaskCallback***:
|
|
33
|
+
* one-shot callback used by `setTask`, `setLockTask` and `setThrottleTask`.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const callback: TaskCallback = () => {
|
|
37
|
+
* doSomething();
|
|
38
|
+
* };
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
type TaskCallback = () => void;
|
|
42
|
+
/**---
|
|
43
|
+
* ## 
|
|
44
|
+
* ### ***LoopTaskCallback***:
|
|
45
|
+
* repeated callback used by `setLoopTask`.
|
|
46
|
+
* @param tick 1-based loop iteration count.
|
|
47
|
+
* @param time current time from `performance.now()` / RAF timestamp.
|
|
48
|
+
* @param delta time passed since the previous loop tick.
|
|
49
|
+
* @returns `false` to stop the loop.
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* setLoopTask((tick, time, delta) => {
|
|
53
|
+
* doSomething();
|
|
54
|
+
*
|
|
55
|
+
* if (tick > 10) return false;
|
|
56
|
+
* }, "raf", "my-key");
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
type LoopTaskCallback = (tick: number, time: number, delta: number) => boolean | void;
|
|
60
|
+
type Task = {
|
|
61
|
+
key: string;
|
|
62
|
+
callback: TaskCallback;
|
|
63
|
+
runAt: number;
|
|
64
|
+
};
|
|
65
|
+
/**---
|
|
66
|
+
* ## 
|
|
67
|
+
* ### ***CancelTaskData***:
|
|
68
|
+
* input accepted by `cancelTask`.
|
|
69
|
+
* @description
|
|
70
|
+
* - `TaskKey`: *cancel one task by key*
|
|
71
|
+
* - `TaskKey[]`: *cancel several tasks by key*
|
|
72
|
+
* - `undefined`: *cancel everything in the manager*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* cancelTask("my-key");
|
|
76
|
+
* cancelTask(["key1", "key2"]);
|
|
77
|
+
* cancelTask();
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
type CancelTaskData = TaskKey | TaskKey[];
|
|
81
|
+
/**---
|
|
82
|
+
* ## 
|
|
83
|
+
* ### ***TaskManager***:
|
|
84
|
+
* isolated key-based task manager.
|
|
85
|
+
* @description
|
|
86
|
+
* Use `createTaskManager()` when a component, scene, entity or module needs its own task state and cleanup.
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* const tasks = createTaskManager();
|
|
90
|
+
*
|
|
91
|
+
* tasks.setLoopTask(callback, "raf", "my-raf-key");
|
|
92
|
+
* tasks.setTask(callback, 1000, "my-timeout-key");
|
|
93
|
+
*
|
|
94
|
+
* tasks.clear();
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
type TaskManager = {
|
|
98
|
+
/**---
|
|
99
|
+
* ## 
|
|
100
|
+
* ### ***setTask***:
|
|
101
|
+
* schedule latest one-shot work by timeout or RAF.
|
|
102
|
+
* @description
|
|
103
|
+
* If the same `key` is used again, the previous task state is replaced.
|
|
104
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* manager.setTask(() => {
|
|
108
|
+
* doSomething();
|
|
109
|
+
* }, "raf", "my-key");
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
setTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
113
|
+
/**---
|
|
114
|
+
* ## 
|
|
115
|
+
* ### ***setLockTask***:
|
|
116
|
+
* run work immediately, then lock repeated calls by key.
|
|
117
|
+
* @description
|
|
118
|
+
* The first call wins. Calls with a key that already belongs to a task state are ignored until that key becomes free.
|
|
119
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* manager.setLockTask(() => {
|
|
123
|
+
* doSomething();
|
|
124
|
+
* }, "raf", "my-key");
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
setLockTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
128
|
+
/**---
|
|
129
|
+
* ## 
|
|
130
|
+
* ### ***setThrottleTask***:
|
|
131
|
+
* run work immediately, then keep the latest repeated call while throttled.
|
|
132
|
+
* @description
|
|
133
|
+
* The first call runs immediately. Calls with the same `key` during the throttle window save only the latest callback, which runs when the window opens again.
|
|
134
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* manager.setThrottleTask(() => {
|
|
138
|
+
* doSomething();
|
|
139
|
+
* }, "raf", "my-key");
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
setThrottleTask: (callback: TaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
143
|
+
/**---
|
|
144
|
+
* ## 
|
|
145
|
+
* ### ***setLoopTask***:
|
|
146
|
+
* run repeated work by timeout or RAF.
|
|
147
|
+
* @description
|
|
148
|
+
* If the same `key` is used again, the previous task state is cancelled and replaced. Return `false` from callback to stop the loop.
|
|
149
|
+
* @returns the passed key, or an automatically generated key when `key` is omitted.
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* manager.setLoopTask((tick, time, delta) => {
|
|
153
|
+
* doSomething();
|
|
154
|
+
*
|
|
155
|
+
* if (tick > 10) return false;
|
|
156
|
+
* }, "raf", "my-key");
|
|
157
|
+
* ```
|
|
158
|
+
*/
|
|
159
|
+
setLoopTask: (callback: LoopTaskCallback, timer: TaskTimer, key?: TaskKey) => string;
|
|
160
|
+
/**---
|
|
161
|
+
* ## 
|
|
162
|
+
* ### ***cancelTask***:
|
|
163
|
+
* cancel one task, several tasks or all tasks in the manager.
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* manager.cancelTask("my-key");
|
|
167
|
+
* manager.cancelTask(["key1", "key2"]);
|
|
168
|
+
* manager.cancelTask();
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
cancelTask: (taskData?: CancelTaskData) => void;
|
|
172
|
+
/**---
|
|
173
|
+
* ## 
|
|
174
|
+
* ### ***hasTask***:
|
|
175
|
+
* check whether a key belongs to any active task state.
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* if (manager.hasTask("my-key")) {
|
|
179
|
+
* manager.cancelTask("my-key");
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
hasTask: (key: TaskKey) => boolean;
|
|
184
|
+
/**---
|
|
185
|
+
* ## 
|
|
186
|
+
* ### ***clear***:
|
|
187
|
+
* cancel every pending one-shot task, active lock, active throttle and active loop in this manager.
|
|
188
|
+
* @example
|
|
189
|
+
* ```ts
|
|
190
|
+
* tasks.clear();
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
clear: () => void;
|
|
194
|
+
};
|
|
195
|
+
export type { CancelTaskData, LoopTaskCallback, Task, TaskCallback, TaskKey, TaskManager, TaskTimer, };
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "keytask-core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A tiny key-based task controller for timeout and RAF work.",
|
|
5
|
+
"author": "Georg Schilin",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/cjs/index.cjs",
|
|
9
|
+
"module": "dist/esm/index.js",
|
|
10
|
+
"types": "dist/types/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"import": "./dist/esm/index.js",
|
|
15
|
+
"require": "./dist/cjs/index.cjs"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/voodoofugu/keytask.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/voodoofugu/keytask#readme",
|
|
23
|
+
"keywords": [
|
|
24
|
+
"keytask",
|
|
25
|
+
"task",
|
|
26
|
+
"keyed",
|
|
27
|
+
"timer",
|
|
28
|
+
"timeout",
|
|
29
|
+
"raf",
|
|
30
|
+
"animation",
|
|
31
|
+
"game-loop",
|
|
32
|
+
"throttle",
|
|
33
|
+
"scheduler"
|
|
34
|
+
],
|
|
35
|
+
"sideEffects": false,
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"README.md",
|
|
39
|
+
"LICENSE"
|
|
40
|
+
]
|
|
41
|
+
}
|