@x-oasis/batchinate-last 0.1.36 → 0.1.38
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/.turbo/turbo-build.log +5 -11
- package/CHANGELOG.md +14 -0
- package/README.md +272 -7
- package/dist/batchinate-last.cjs.development.js +71 -43
- package/dist/batchinate-last.cjs.development.js.map +1 -1
- package/dist/batchinate-last.cjs.production.min.js +1 -1
- package/dist/batchinate-last.cjs.production.min.js.map +1 -1
- package/dist/batchinate-last.esm.js +69 -43
- package/dist/batchinate-last.esm.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/package.json +4 -1
- package/src/index.ts +113 -53
- package/test/test.spec.ts +247 -3
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
1
|
|
|
2
|
-
> @x-oasis/batchinate-last@0.1.
|
|
2
|
+
> @x-oasis/batchinate-last@0.1.38 build /home/runner/work/x-oasis/x-oasis/packages/schedule/batchinate-last
|
|
3
3
|
> tsdx build --tsconfig tsconfig.build.json
|
|
4
4
|
|
|
5
5
|
@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
|
|
6
6
|
@rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
|
|
7
7
|
⠙ Creating entry file
|
|
8
|
-
[2K[1A[2K[G
|
|
9
|
-
|
|
10
|
-
⠹ Building modules
|
|
8
|
+
[2K[1A[2K[G✓ Creating entry file 2.4 secs
|
|
9
|
+
⠙ Building modules
|
|
10
|
+
[2K[1A[2K[G⠹ Building modules
|
|
11
11
|
[2K[1A[2K[G⠸ Building modules
|
|
12
|
-
[2K[1A[2K[G⠼ Building modules
|
|
13
|
-
[2K[1A[2K[G⠴ Building modules
|
|
14
|
-
[2K[1A[2K[G⠦ Building modules
|
|
15
|
-
[2K[1A[2K[G⠧ Building modules
|
|
16
|
-
[2K[1A[2K[G⠇ Building modules
|
|
17
12
|
[tsdx]: Your rootDir is currently set to "./". Please change your rootDir to "./src".
|
|
18
13
|
TSDX has deprecated setting tsconfig.compilerOptions.rootDir to "./" as it caused buggy output for declarationMaps and more.
|
|
19
14
|
You may also need to change your include to remove "test", which also caused declarations to be unnecessarily created for test files.
|
|
20
|
-
[2K[1A[2K[G
|
|
21
|
-
[2K[1A[2K[G✓ Building modules 9.8 secs
|
|
15
|
+
[2K[1A[2K[G✓ Building modules 4 secs
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @x-oasis/batchinate-last
|
|
2
2
|
|
|
3
|
+
## 0.1.38
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f1aae14: bump version
|
|
8
|
+
- Updated dependencies [f1aae14]
|
|
9
|
+
- @x-oasis/debounce@0.1.38
|
|
10
|
+
|
|
11
|
+
## 0.1.37
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- 8cb524c: trigger next
|
|
16
|
+
|
|
3
17
|
## 0.1.36
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -1,19 +1,284 @@
|
|
|
1
1
|
# @x-oasis/batchinate-last
|
|
2
2
|
|
|
3
|
+
Executes the callback with the last arguments after a delay. If `schedule` is called multiple times within the delay period, only the last call's arguments will be used when the callback executes.
|
|
4
|
+
|
|
5
|
+
This is useful for scenarios where you want to batch multiple rapid calls and only process the final state.
|
|
6
|
+
|
|
3
7
|
## Installation
|
|
4
8
|
|
|
5
9
|
```bash
|
|
6
|
-
|
|
10
|
+
npm install @x-oasis/batchinate-last
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @x-oasis/batchinate-last
|
|
13
|
+
# or
|
|
14
|
+
yarn add @x-oasis/batchinate-last
|
|
7
15
|
```
|
|
8
16
|
|
|
9
|
-
##
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Basic Usage
|
|
10
20
|
|
|
11
21
|
```typescript
|
|
12
|
-
import
|
|
22
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
23
|
+
|
|
24
|
+
const callback = (message: string) => {
|
|
25
|
+
console.log(message);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const batchinator = new BatchinateLast(callback, 100);
|
|
29
|
+
|
|
30
|
+
// Schedule multiple calls
|
|
31
|
+
batchinator.schedule('First');
|
|
32
|
+
batchinator.schedule('Second');
|
|
33
|
+
batchinator.schedule('Third');
|
|
34
|
+
|
|
35
|
+
// Only 'Third' will execute after 100ms
|
|
13
36
|
```
|
|
14
37
|
|
|
15
|
-
|
|
38
|
+
### Flush Scheduled Task
|
|
16
39
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
```
|
|
40
|
+
Immediately execute the scheduled task:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
44
|
+
|
|
45
|
+
const batchinator = new BatchinateLast(callback, 100);
|
|
46
|
+
|
|
47
|
+
batchinator.schedule('First');
|
|
48
|
+
batchinator.schedule('Second');
|
|
49
|
+
batchinator.flush(); // Executes immediately with 'Second'
|
|
50
|
+
|
|
51
|
+
// Or flush with new arguments
|
|
52
|
+
batchinator.flush('Custom');
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Dispose
|
|
56
|
+
|
|
57
|
+
Cancel the scheduled task and optionally execute it:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
61
|
+
|
|
62
|
+
const batchinator = new BatchinateLast(callback, 100);
|
|
63
|
+
|
|
64
|
+
batchinator.schedule('First');
|
|
65
|
+
batchinator.schedule('Second');
|
|
66
|
+
|
|
67
|
+
// Dispose and execute
|
|
68
|
+
batchinator.dispose(); // Executes with 'Second'
|
|
69
|
+
|
|
70
|
+
// Dispose without executing
|
|
71
|
+
batchinator.dispose({ abort: true }); // Cancels without executing
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Check Schedule Status
|
|
75
|
+
|
|
76
|
+
Check if a task is currently scheduled:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
80
|
+
|
|
81
|
+
const batchinator = new BatchinateLast(callback, 100);
|
|
82
|
+
|
|
83
|
+
batchinator.schedule('First');
|
|
84
|
+
console.log(batchinator.inSchedule()); // true
|
|
85
|
+
|
|
86
|
+
// After execution or cancel
|
|
87
|
+
batchinator.flush();
|
|
88
|
+
console.log(batchinator.inSchedule()); // false
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Continuous Scheduling
|
|
92
|
+
|
|
93
|
+
If new calls are made during execution, the handler will automatically reschedule:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
97
|
+
|
|
98
|
+
const batchinator = new BatchinateLast(callback, 100);
|
|
99
|
+
|
|
100
|
+
batchinator.schedule('First');
|
|
101
|
+
// ... 50ms later
|
|
102
|
+
batchinator.schedule('Second');
|
|
103
|
+
// ... 50ms later (during execution)
|
|
104
|
+
batchinator.schedule('Third');
|
|
105
|
+
// Handler will reschedule to execute 'Third'
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
### `new BatchinateLast(callback, delayMS)`
|
|
111
|
+
|
|
112
|
+
Creates a new BatchinateLast instance.
|
|
113
|
+
|
|
114
|
+
#### Parameters
|
|
115
|
+
|
|
116
|
+
- `callback` (`Function`): The function to execute with the last arguments.
|
|
117
|
+
- `delayMS` (`number`): The delay in milliseconds before executing the callback.
|
|
118
|
+
|
|
119
|
+
#### Returns
|
|
120
|
+
|
|
121
|
+
Returns a new `BatchinateLast` instance.
|
|
122
|
+
|
|
123
|
+
### Instance Methods
|
|
124
|
+
|
|
125
|
+
#### `schedule(...args)`
|
|
126
|
+
|
|
127
|
+
Schedule the callback to execute after `delayMS`. If called multiple times, only the last call's arguments will be used.
|
|
128
|
+
|
|
129
|
+
- `args` (`...any[]`): Arguments to pass to the callback.
|
|
130
|
+
|
|
131
|
+
#### `flush(...args)`
|
|
132
|
+
|
|
133
|
+
Immediately execute the scheduled task. If arguments are provided, they will be used instead of stored arguments.
|
|
134
|
+
|
|
135
|
+
- `args` (`...any[]`, optional): Optional arguments to use instead of stored args.
|
|
136
|
+
|
|
137
|
+
#### `dispose(options?)`
|
|
138
|
+
|
|
139
|
+
Dispose the scheduled task. By default, executes the callback with stored arguments unless `abort` is `true`.
|
|
140
|
+
|
|
141
|
+
- `options` (`Object`, optional): Configuration options.
|
|
142
|
+
- `abort` (`boolean`, default: `false`): If `true`, cancel without executing callback.
|
|
143
|
+
|
|
144
|
+
#### `inSchedule()`
|
|
145
|
+
|
|
146
|
+
Check if a task is currently scheduled.
|
|
147
|
+
|
|
148
|
+
- Returns: `boolean` - `true` if a task is scheduled, `false` otherwise.
|
|
149
|
+
|
|
150
|
+
## Examples
|
|
151
|
+
|
|
152
|
+
### Search Input
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
156
|
+
|
|
157
|
+
const performSearch = (query: string) => {
|
|
158
|
+
// Perform search with query
|
|
159
|
+
console.log('Searching for:', query);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
const batchinator = new BatchinateLast(performSearch, 300);
|
|
163
|
+
|
|
164
|
+
// User types in search box
|
|
165
|
+
input.addEventListener('input', (e) => {
|
|
166
|
+
batchinator.schedule(e.target.value);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Only the final query executes after user stops typing
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Window Resize Handler
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
176
|
+
|
|
177
|
+
const handleResize = (width: number, height: number) => {
|
|
178
|
+
// Recalculate layout
|
|
179
|
+
console.log('Resized to:', width, height);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const batchinator = new BatchinateLast(handleResize, 200);
|
|
183
|
+
|
|
184
|
+
window.addEventListener('resize', () => {
|
|
185
|
+
batchinator.schedule(window.innerWidth, window.innerHeight);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// Only the final dimensions are processed
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Form Auto-save
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
195
|
+
|
|
196
|
+
const saveForm = (formData: any) => {
|
|
197
|
+
// Save form data
|
|
198
|
+
console.log('Saving form:', formData);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
const batchinator = new BatchinateLast(saveForm, 1000);
|
|
202
|
+
|
|
203
|
+
form.addEventListener('input', () => {
|
|
204
|
+
const formData = new FormData(form);
|
|
205
|
+
batchinator.schedule(Object.fromEntries(formData));
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Form saves 1 second after user stops editing
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Scroll Position Tracking
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
215
|
+
|
|
216
|
+
const updateScrollPosition = (x: number, y: number) => {
|
|
217
|
+
// Update scroll position in state
|
|
218
|
+
console.log('Scroll position:', x, y);
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const batchinator = new BatchinateLast(updateScrollPosition, 100);
|
|
222
|
+
|
|
223
|
+
window.addEventListener('scroll', () => {
|
|
224
|
+
batchinator.schedule(window.scrollX, window.scrollY);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// Only the final scroll position is tracked
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Cleanup on Component Unmount
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import BatchinateLast from '@x-oasis/batchinate-last';
|
|
234
|
+
import { useEffect } from 'react';
|
|
235
|
+
|
|
236
|
+
function MyComponent() {
|
|
237
|
+
const batchinator = new BatchinateLast(handleUpdate, 100);
|
|
238
|
+
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
// Use batchinator
|
|
241
|
+
batchinator.schedule(data);
|
|
242
|
+
|
|
243
|
+
// Cleanup on unmount
|
|
244
|
+
return () => {
|
|
245
|
+
batchinator.dispose({ abort: true });
|
|
246
|
+
};
|
|
247
|
+
}, []);
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Differences from Other Utilities
|
|
252
|
+
|
|
253
|
+
### vs Debounce
|
|
254
|
+
|
|
255
|
+
- **BatchinateLast**: Always uses the last arguments, executes after a fixed delay.
|
|
256
|
+
- **Debounce**: Resets the delay timer on each call, executes only after a period of inactivity.
|
|
257
|
+
|
|
258
|
+
### vs Throttle
|
|
259
|
+
|
|
260
|
+
- **BatchinateLast**: Executes once with the last arguments after the delay.
|
|
261
|
+
- **Throttle**: Executes at most once per period, regardless of call frequency.
|
|
262
|
+
|
|
263
|
+
### vs Batchinator
|
|
264
|
+
|
|
265
|
+
- **BatchinateLast**: Simpler, always executes with last arguments after delay.
|
|
266
|
+
- **Batchinator**: More configurable, supports leading/trailing execution options.
|
|
267
|
+
|
|
268
|
+
## When to Use BatchinateLast
|
|
269
|
+
|
|
270
|
+
- Search input debouncing
|
|
271
|
+
- Window resize handlers
|
|
272
|
+
- Form auto-save
|
|
273
|
+
- Scroll position tracking
|
|
274
|
+
- Any scenario where you want to batch rapid calls and only process the final state
|
|
275
|
+
|
|
276
|
+
## See Also
|
|
277
|
+
|
|
278
|
+
- [@x-oasis/batchinator](../batchinator/README.md) - Batches with leading/trailing options
|
|
279
|
+
- [@x-oasis/debounce](../debounce/README.md) - Creates a debounced function
|
|
280
|
+
- [@x-oasis/throttle](../throttle/README.md) - Creates a throttled function
|
|
281
|
+
|
|
282
|
+
## License
|
|
283
|
+
|
|
284
|
+
ISC
|
|
@@ -2,13 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
|
6
|
+
|
|
7
|
+
var debounce = _interopDefault(require('@x-oasis/debounce'));
|
|
8
|
+
|
|
5
9
|
var BatchinateLast = /*#__PURE__*/function () {
|
|
6
10
|
function BatchinateLast(cb, delayMS) {
|
|
11
|
+
var _this = this;
|
|
12
|
+
this._storedArgs = null;
|
|
13
|
+
this._isScheduled = false;
|
|
14
|
+
this._clockTime = 0;
|
|
15
|
+
this._lastTime = 0;
|
|
16
|
+
this._rescheduleHandler = null;
|
|
7
17
|
this._callback = cb;
|
|
8
18
|
this._delayMS = delayMS;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
var executeAndReschedule = function executeAndReschedule() {
|
|
20
|
+
var savedClockTime = _this._clockTime;
|
|
21
|
+
_this._isScheduled = false;
|
|
22
|
+
if (_this._rescheduleHandler) {
|
|
23
|
+
_this._rescheduleHandler.cancel();
|
|
24
|
+
_this._rescheduleHandler = null;
|
|
25
|
+
}
|
|
26
|
+
if (_this._storedArgs !== null) {
|
|
27
|
+
_this._callback.apply(_this, _this._storedArgs);
|
|
28
|
+
}
|
|
29
|
+
if (_this._delayMS && savedClockTime !== _this._lastTime) {
|
|
30
|
+
var now = Date.now();
|
|
31
|
+
var elapsedTime = now - _this._lastTime;
|
|
32
|
+
var timeoutTime = Math.max(_this._delayMS - elapsedTime, 0);
|
|
33
|
+
_this._clockTime = now;
|
|
34
|
+
var timeoutHandle = setTimeout(function () {
|
|
35
|
+
executeAndReschedule();
|
|
36
|
+
}, timeoutTime);
|
|
37
|
+
_this._rescheduleHandler = {
|
|
38
|
+
cancel: function cancel() {
|
|
39
|
+
return clearTimeout(timeoutHandle);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
_this._isScheduled = true;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
this._debounced = debounce(executeAndReschedule, delayMS, {
|
|
46
|
+
leading: false,
|
|
47
|
+
trailing: true
|
|
48
|
+
});
|
|
12
49
|
}
|
|
13
50
|
var _proto = BatchinateLast.prototype;
|
|
14
51
|
_proto.dispose = function dispose(options) {
|
|
@@ -18,67 +55,58 @@ var BatchinateLast = /*#__PURE__*/function () {
|
|
|
18
55
|
};
|
|
19
56
|
}
|
|
20
57
|
var _options = options,
|
|
21
|
-
abort = _options.abort
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
this.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
58
|
+
_options$abort = _options.abort,
|
|
59
|
+
abort = _options$abort === void 0 ? false : _options$abort;
|
|
60
|
+
if (abort) {
|
|
61
|
+
this._debounced.cancel();
|
|
62
|
+
if (this._rescheduleHandler) {
|
|
63
|
+
this._rescheduleHandler.cancel();
|
|
64
|
+
this._rescheduleHandler = null;
|
|
65
|
+
}
|
|
66
|
+
this._isScheduled = false;
|
|
67
|
+
this._storedArgs = null;
|
|
68
|
+
} else {
|
|
69
|
+
if (this._storedArgs !== null) {
|
|
70
|
+
this._debounced.flush();
|
|
71
|
+
}
|
|
28
72
|
}
|
|
29
73
|
};
|
|
30
74
|
_proto.inSchedule = function inSchedule() {
|
|
31
|
-
return
|
|
75
|
+
return this._isScheduled || this._rescheduleHandler !== null;
|
|
32
76
|
};
|
|
33
77
|
_proto.flush = function flush() {
|
|
34
78
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
35
79
|
args[_key] = arguments[_key];
|
|
36
80
|
}
|
|
37
|
-
if (args.length
|
|
38
|
-
|
|
39
|
-
_proto.handler = function handler() {
|
|
40
|
-
var _this = this;
|
|
41
|
-
if (this._taskHandler) {
|
|
42
|
-
this._taskHandler.cancel();
|
|
43
|
-
this._taskHandler = null;
|
|
81
|
+
if (args.length > 0) {
|
|
82
|
+
this._storedArgs = args;
|
|
44
83
|
}
|
|
45
|
-
this.
|
|
46
|
-
if (this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
this._clockTime = Date.now();
|
|
50
|
-
var timeoutHandler = setTimeout(function () {
|
|
51
|
-
_this.handler();
|
|
52
|
-
}, timeoutTime);
|
|
53
|
-
this._taskHandler = {
|
|
54
|
-
cancel: function cancel() {
|
|
55
|
-
return clearTimeout(timeoutHandler);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
84
|
+
this._debounced.flush();
|
|
85
|
+
if (this._rescheduleHandler) {
|
|
86
|
+
this._rescheduleHandler.cancel();
|
|
87
|
+
this._rescheduleHandler = null;
|
|
58
88
|
}
|
|
89
|
+
this._isScheduled = false;
|
|
59
90
|
};
|
|
60
91
|
_proto.schedule = function schedule() {
|
|
61
|
-
var _this2 = this;
|
|
62
92
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
63
93
|
args[_key2] = arguments[_key2];
|
|
64
94
|
}
|
|
65
|
-
this.
|
|
95
|
+
this._storedArgs = args;
|
|
66
96
|
var now = Date.now();
|
|
67
97
|
this._lastTime = now;
|
|
68
|
-
if (this._taskHandler) return;
|
|
69
98
|
if (!this._delayMS) {
|
|
70
|
-
this.
|
|
99
|
+
if (this._storedArgs !== null) {
|
|
100
|
+
this._callback.apply(this, this._storedArgs);
|
|
101
|
+
}
|
|
71
102
|
return;
|
|
72
103
|
}
|
|
104
|
+
if (this._isScheduled) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
this._isScheduled = true;
|
|
73
108
|
this._clockTime = now;
|
|
74
|
-
|
|
75
|
-
_this2.handler();
|
|
76
|
-
}, this._delayMS);
|
|
77
|
-
this._taskHandler = {
|
|
78
|
-
cancel: function cancel() {
|
|
79
|
-
return clearTimeout(timeoutHandler);
|
|
80
|
-
}
|
|
81
|
-
};
|
|
109
|
+
this._debounced();
|
|
82
110
|
};
|
|
83
111
|
return BatchinateLast;
|
|
84
112
|
}();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batchinate-last.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"batchinate-last.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * BatchinateLast - Executes the callback with the last arguments after a delay.\n * If schedule is called multiple times within the delay period, only the last\n * call's arguments will be used when the callback executes.\n */\ntype TaskHandler = {\n cancel: () => void;\n};\n\nclass BatchinateLast {\n readonly _delayMS: number;\n private _callback: (...args: any[]) => void;\n private _debounced: ReturnType<typeof debounce>;\n private _storedArgs: any[] | null = null;\n private _isScheduled = false;\n private _clockTime = 0;\n private _lastTime = 0;\n private _rescheduleHandler: TaskHandler | null = null;\n\n constructor(cb: (...args: any[]) => void, delayMS: number) {\n this._callback = cb;\n this._delayMS = delayMS;\n\n // Helper function to handle execution and potential rescheduling\n const executeAndReschedule = (): void => {\n const savedClockTime = this._clockTime;\n this._isScheduled = false;\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n\n // Check if there were new calls during execution\n // If lastTime was updated (clockTime !== lastTime), reschedule\n if (this._delayMS && savedClockTime !== this._lastTime) {\n const now = Date.now();\n const elapsedTime = now - this._lastTime;\n const timeoutTime = Math.max(this._delayMS - elapsedTime, 0);\n this._clockTime = now;\n\n // Reschedule with remaining time\n const timeoutHandle = setTimeout(() => {\n executeAndReschedule();\n }, timeoutTime);\n this._rescheduleHandler = { cancel: () => clearTimeout(timeoutHandle) };\n this._isScheduled = true;\n }\n };\n\n // Create a debounced function\n // Special behavior: if new calls occur during execution, reschedule\n this._debounced = debounce(executeAndReschedule, delayMS, {\n leading: false,\n trailing: true,\n });\n }\n\n /**\n * Dispose the scheduled task\n * @param options - Configuration options\n * @param options.abort - If true, cancel without executing callback\n */\n dispose(\n options: {\n abort?: boolean;\n } = {\n abort: false,\n }\n ): void {\n const { abort = false } = options;\n if (abort) {\n this._debounced.cancel();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n this._storedArgs = null;\n } else {\n // Execute with current args if any\n if (this._storedArgs !== null) {\n this._debounced.flush();\n }\n }\n }\n\n /**\n * Check if a task is currently scheduled\n */\n inSchedule(): boolean {\n return this._isScheduled || this._rescheduleHandler !== null;\n }\n\n /**\n * Flush the scheduled task immediately\n * @param args - Optional arguments to use instead of stored args\n */\n flush(...args: any[]): void {\n if (args.length > 0) {\n this._storedArgs = args;\n }\n this._debounced.flush();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n }\n\n /**\n * Schedule the callback to execute after delayMS\n * If called multiple times, only the last call's arguments will be used\n * @param args - Arguments to pass to the callback\n */\n schedule(...args: any[]): void {\n this._storedArgs = args;\n const now = Date.now();\n this._lastTime = now;\n\n // Handle zero delay case - execute immediately\n if (!this._delayMS) {\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n return;\n }\n\n // If already scheduled, just update args and return (don't reset timer)\n if (this._isScheduled) {\n return;\n }\n\n // First call - mark as scheduled and call debounce\n this._isScheduled = true;\n this._clockTime = now;\n this._debounced();\n }\n}\n\nexport default BatchinateLast;\n"],"names":["BatchinateLast","cb","delayMS","_callback","_delayMS","executeAndReschedule","savedClockTime","_this","_clockTime","_isScheduled","_rescheduleHandler","cancel","_storedArgs","apply","_lastTime","now","Date","elapsedTime","timeoutTime","Math","max","timeoutHandle","setTimeout","clearTimeout","_debounced","debounce","leading","trailing","_proto","prototype","dispose","options","abort","_options","_options$abort","flush","inSchedule","args","Array","_len","_key","arguments","length","schedule","_len2","_key2"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.default=function(){function
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e,l=(e=require("@x-oasis/debounce"))&&"object"==typeof e&&"default"in e?e.default:e;exports.default=function(){function e(e,s){var t=this;this._storedArgs=null,this._isScheduled=!1,this._clockTime=0,this._lastTime=0,this._rescheduleHandler=null,this._callback=e,this._delayMS=s,this._debounced=l((function e(){var l=t._clockTime;if(t._isScheduled=!1,t._rescheduleHandler&&(t._rescheduleHandler.cancel(),t._rescheduleHandler=null),null!==t._storedArgs&&t._callback.apply(t,t._storedArgs),t._delayMS&&l!==t._lastTime){var s=Date.now(),i=Math.max(t._delayMS-(s-t._lastTime),0);t._clockTime=s;var r=setTimeout((function(){e()}),i);t._rescheduleHandler={cancel:function(){return clearTimeout(r)}},t._isScheduled=!0}}),s,{leading:!1,trailing:!0})}var s=e.prototype;return s.dispose=function(e){void 0===e&&(e={abort:!1});var l=e.abort;void 0!==l&&l?(this._debounced.cancel(),this._rescheduleHandler&&(this._rescheduleHandler.cancel(),this._rescheduleHandler=null),this._isScheduled=!1,this._storedArgs=null):null!==this._storedArgs&&this._debounced.flush()},s.inSchedule=function(){return this._isScheduled||null!==this._rescheduleHandler},s.flush=function(){for(var e=arguments.length,l=new Array(e),s=0;s<e;s++)l[s]=arguments[s];l.length>0&&(this._storedArgs=l),this._debounced.flush(),this._rescheduleHandler&&(this._rescheduleHandler.cancel(),this._rescheduleHandler=null),this._isScheduled=!1},s.schedule=function(){for(var e=arguments.length,l=new Array(e),s=0;s<e;s++)l[s]=arguments[s];this._storedArgs=l;var t=Date.now();this._lastTime=t,this._delayMS?this._isScheduled||(this._isScheduled=!0,this._clockTime=t,this._debounced()):null!==this._storedArgs&&this._callback.apply(this,this._storedArgs)},e}();
|
|
2
2
|
//# sourceMappingURL=batchinate-last.cjs.production.min.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batchinate-last.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"batchinate-last.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * BatchinateLast - Executes the callback with the last arguments after a delay.\n * If schedule is called multiple times within the delay period, only the last\n * call's arguments will be used when the callback executes.\n */\ntype TaskHandler = {\n cancel: () => void;\n};\n\nclass BatchinateLast {\n readonly _delayMS: number;\n private _callback: (...args: any[]) => void;\n private _debounced: ReturnType<typeof debounce>;\n private _storedArgs: any[] | null = null;\n private _isScheduled = false;\n private _clockTime = 0;\n private _lastTime = 0;\n private _rescheduleHandler: TaskHandler | null = null;\n\n constructor(cb: (...args: any[]) => void, delayMS: number) {\n this._callback = cb;\n this._delayMS = delayMS;\n\n // Helper function to handle execution and potential rescheduling\n const executeAndReschedule = (): void => {\n const savedClockTime = this._clockTime;\n this._isScheduled = false;\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n\n // Check if there were new calls during execution\n // If lastTime was updated (clockTime !== lastTime), reschedule\n if (this._delayMS && savedClockTime !== this._lastTime) {\n const now = Date.now();\n const elapsedTime = now - this._lastTime;\n const timeoutTime = Math.max(this._delayMS - elapsedTime, 0);\n this._clockTime = now;\n\n // Reschedule with remaining time\n const timeoutHandle = setTimeout(() => {\n executeAndReschedule();\n }, timeoutTime);\n this._rescheduleHandler = { cancel: () => clearTimeout(timeoutHandle) };\n this._isScheduled = true;\n }\n };\n\n // Create a debounced function\n // Special behavior: if new calls occur during execution, reschedule\n this._debounced = debounce(executeAndReschedule, delayMS, {\n leading: false,\n trailing: true,\n });\n }\n\n /**\n * Dispose the scheduled task\n * @param options - Configuration options\n * @param options.abort - If true, cancel without executing callback\n */\n dispose(\n options: {\n abort?: boolean;\n } = {\n abort: false,\n }\n ): void {\n const { abort = false } = options;\n if (abort) {\n this._debounced.cancel();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n this._storedArgs = null;\n } else {\n // Execute with current args if any\n if (this._storedArgs !== null) {\n this._debounced.flush();\n }\n }\n }\n\n /**\n * Check if a task is currently scheduled\n */\n inSchedule(): boolean {\n return this._isScheduled || this._rescheduleHandler !== null;\n }\n\n /**\n * Flush the scheduled task immediately\n * @param args - Optional arguments to use instead of stored args\n */\n flush(...args: any[]): void {\n if (args.length > 0) {\n this._storedArgs = args;\n }\n this._debounced.flush();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n }\n\n /**\n * Schedule the callback to execute after delayMS\n * If called multiple times, only the last call's arguments will be used\n * @param args - Arguments to pass to the callback\n */\n schedule(...args: any[]): void {\n this._storedArgs = args;\n const now = Date.now();\n this._lastTime = now;\n\n // Handle zero delay case - execute immediately\n if (!this._delayMS) {\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n return;\n }\n\n // If already scheduled, just update args and return (don't reset timer)\n if (this._isScheduled) {\n return;\n }\n\n // First call - mark as scheduled and call debounce\n this._isScheduled = true;\n this._clockTime = now;\n this._debounced();\n }\n}\n\nexport default BatchinateLast;\n"],"names":["BatchinateLast","cb","delayMS","this","_callback","_delayMS","_debounced","debounce","executeAndReschedule","savedClockTime","_this","_clockTime","_isScheduled","_rescheduleHandler","cancel","_storedArgs","apply","_lastTime","now","Date","timeoutTime","Math","max","timeoutHandle","setTimeout","clearTimeout","leading","trailing","_proto","prototype","dispose","options","abort","_options$abort","flush","inSchedule","args","Array","_len","_key","arguments","length","schedule","_len2","_key2"],"mappings":"uLAqBE,SAAAA,EAAYC,EAA8BC,cANlCC,iBAA4B,KAC5BA,mBAAe,EACfA,gBAAa,EACbA,eAAY,EACZA,wBAAyC,KAG/CA,KAAKC,UAAYH,EACjBE,KAAKE,SAAWH,EAkChBC,KAAKG,WAAaC,GA/BW,SAAvBC,IACJ,IAAMC,EAAiBC,EAAKC,WAa5B,GAZAD,EAAKE,cAAe,EAChBF,EAAKG,qBACPH,EAAKG,mBAAmBC,SACxBJ,EAAKG,mBAAqB,MAGH,OAArBH,EAAKK,aACPL,EAAKN,UAASY,MAAdN,EAAkBA,EAAKK,aAKrBL,EAAKL,UAAYI,IAAmBC,EAAKO,UAAW,CACtD,IAAMC,EAAMC,KAAKD,MAEXE,EAAcC,KAAKC,IAAIZ,EAAKL,UADda,EAAMR,EAAKO,WAC2B,GAC1DP,EAAKC,WAAaO,EAGlB,IAAMK,EAAgBC,YAAW,WAC/BhB,MACCY,GACHV,EAAKG,mBAAqB,CAAEC,OAAQ,WAAA,OAAMW,aAAaF,KACvDb,EAAKE,cAAe,KAMyBV,EAAS,CACxDwB,SAAS,EACTC,UAAU,IAEb,IAAAC,EAAA5B,EAAA6B,UAiFA,OAjFAD,EAODE,QAAA,SACEC,YAAAA,IAAAA,EAEI,CACFC,OAAO,IAGT,IAAiCC,EAAPF,EAAlBC,eAAKC,GAAQA,GAEnB9B,KAAKG,WAAWQ,SACZX,KAAKU,qBACPV,KAAKU,mBAAmBC,SACxBX,KAAKU,mBAAqB,MAE5BV,KAAKS,cAAe,EACpBT,KAAKY,YAAc,MAGM,OAArBZ,KAAKY,aACPZ,KAAKG,WAAW4B,SAGrBN,EAKDO,WAAA,WACE,OAAOhC,KAAKS,cAA4C,OAA5BT,KAAKU,oBAClCe,EAMDM,MAAA,sCAASE,MAAWC,MAAAC,GAAAC,IAAAA,EAAAD,EAAAC,IAAXH,EAAWG,GAAAC,UAAAD,GACdH,EAAKK,OAAS,IAChBtC,KAAKY,YAAcqB,GAErBjC,KAAKG,WAAW4B,QACZ/B,KAAKU,qBACPV,KAAKU,mBAAmBC,SACxBX,KAAKU,mBAAqB,MAE5BV,KAAKS,cAAe,GACrBgB,EAODc,SAAA,sCAAYN,MAAWC,MAAAM,GAAAC,IAAAA,EAAAD,EAAAC,IAAXR,EAAWQ,GAAAJ,UAAAI,GACrBzC,KAAKY,YAAcqB,EACnB,IAAMlB,EAAMC,KAAKD,MACjBf,KAAKc,UAAYC,EAGZf,KAAKE,SAQNF,KAAKS,eAKTT,KAAKS,cAAe,EACpBT,KAAKQ,WAAaO,EAClBf,KAAKG,cAdsB,OAArBH,KAAKY,aACPZ,KAAKC,UAASY,MAAdb,KAAkBA,KAAKY,cAc5Bf"}
|
|
@@ -1,10 +1,45 @@
|
|
|
1
|
+
import debounce from '@x-oasis/debounce';
|
|
2
|
+
|
|
1
3
|
var BatchinateLast = /*#__PURE__*/function () {
|
|
2
4
|
function BatchinateLast(cb, delayMS) {
|
|
5
|
+
var _this = this;
|
|
6
|
+
this._storedArgs = null;
|
|
7
|
+
this._isScheduled = false;
|
|
8
|
+
this._clockTime = 0;
|
|
9
|
+
this._lastTime = 0;
|
|
10
|
+
this._rescheduleHandler = null;
|
|
3
11
|
this._callback = cb;
|
|
4
12
|
this._delayMS = delayMS;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
13
|
+
var executeAndReschedule = function executeAndReschedule() {
|
|
14
|
+
var savedClockTime = _this._clockTime;
|
|
15
|
+
_this._isScheduled = false;
|
|
16
|
+
if (_this._rescheduleHandler) {
|
|
17
|
+
_this._rescheduleHandler.cancel();
|
|
18
|
+
_this._rescheduleHandler = null;
|
|
19
|
+
}
|
|
20
|
+
if (_this._storedArgs !== null) {
|
|
21
|
+
_this._callback.apply(_this, _this._storedArgs);
|
|
22
|
+
}
|
|
23
|
+
if (_this._delayMS && savedClockTime !== _this._lastTime) {
|
|
24
|
+
var now = Date.now();
|
|
25
|
+
var elapsedTime = now - _this._lastTime;
|
|
26
|
+
var timeoutTime = Math.max(_this._delayMS - elapsedTime, 0);
|
|
27
|
+
_this._clockTime = now;
|
|
28
|
+
var timeoutHandle = setTimeout(function () {
|
|
29
|
+
executeAndReschedule();
|
|
30
|
+
}, timeoutTime);
|
|
31
|
+
_this._rescheduleHandler = {
|
|
32
|
+
cancel: function cancel() {
|
|
33
|
+
return clearTimeout(timeoutHandle);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
_this._isScheduled = true;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
this._debounced = debounce(executeAndReschedule, delayMS, {
|
|
40
|
+
leading: false,
|
|
41
|
+
trailing: true
|
|
42
|
+
});
|
|
8
43
|
}
|
|
9
44
|
var _proto = BatchinateLast.prototype;
|
|
10
45
|
_proto.dispose = function dispose(options) {
|
|
@@ -14,67 +49,58 @@ var BatchinateLast = /*#__PURE__*/function () {
|
|
|
14
49
|
};
|
|
15
50
|
}
|
|
16
51
|
var _options = options,
|
|
17
|
-
abort = _options.abort
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
this.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
52
|
+
_options$abort = _options.abort,
|
|
53
|
+
abort = _options$abort === void 0 ? false : _options$abort;
|
|
54
|
+
if (abort) {
|
|
55
|
+
this._debounced.cancel();
|
|
56
|
+
if (this._rescheduleHandler) {
|
|
57
|
+
this._rescheduleHandler.cancel();
|
|
58
|
+
this._rescheduleHandler = null;
|
|
59
|
+
}
|
|
60
|
+
this._isScheduled = false;
|
|
61
|
+
this._storedArgs = null;
|
|
62
|
+
} else {
|
|
63
|
+
if (this._storedArgs !== null) {
|
|
64
|
+
this._debounced.flush();
|
|
65
|
+
}
|
|
24
66
|
}
|
|
25
67
|
};
|
|
26
68
|
_proto.inSchedule = function inSchedule() {
|
|
27
|
-
return
|
|
69
|
+
return this._isScheduled || this._rescheduleHandler !== null;
|
|
28
70
|
};
|
|
29
71
|
_proto.flush = function flush() {
|
|
30
72
|
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
31
73
|
args[_key] = arguments[_key];
|
|
32
74
|
}
|
|
33
|
-
if (args.length
|
|
34
|
-
|
|
35
|
-
_proto.handler = function handler() {
|
|
36
|
-
var _this = this;
|
|
37
|
-
if (this._taskHandler) {
|
|
38
|
-
this._taskHandler.cancel();
|
|
39
|
-
this._taskHandler = null;
|
|
75
|
+
if (args.length > 0) {
|
|
76
|
+
this._storedArgs = args;
|
|
40
77
|
}
|
|
41
|
-
this.
|
|
42
|
-
if (this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this._clockTime = Date.now();
|
|
46
|
-
var timeoutHandler = setTimeout(function () {
|
|
47
|
-
_this.handler();
|
|
48
|
-
}, timeoutTime);
|
|
49
|
-
this._taskHandler = {
|
|
50
|
-
cancel: function cancel() {
|
|
51
|
-
return clearTimeout(timeoutHandler);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
78
|
+
this._debounced.flush();
|
|
79
|
+
if (this._rescheduleHandler) {
|
|
80
|
+
this._rescheduleHandler.cancel();
|
|
81
|
+
this._rescheduleHandler = null;
|
|
54
82
|
}
|
|
83
|
+
this._isScheduled = false;
|
|
55
84
|
};
|
|
56
85
|
_proto.schedule = function schedule() {
|
|
57
|
-
var _this2 = this;
|
|
58
86
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
59
87
|
args[_key2] = arguments[_key2];
|
|
60
88
|
}
|
|
61
|
-
this.
|
|
89
|
+
this._storedArgs = args;
|
|
62
90
|
var now = Date.now();
|
|
63
91
|
this._lastTime = now;
|
|
64
|
-
if (this._taskHandler) return;
|
|
65
92
|
if (!this._delayMS) {
|
|
66
|
-
this.
|
|
93
|
+
if (this._storedArgs !== null) {
|
|
94
|
+
this._callback.apply(this, this._storedArgs);
|
|
95
|
+
}
|
|
67
96
|
return;
|
|
68
97
|
}
|
|
98
|
+
if (this._isScheduled) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this._isScheduled = true;
|
|
69
102
|
this._clockTime = now;
|
|
70
|
-
|
|
71
|
-
_this2.handler();
|
|
72
|
-
}, this._delayMS);
|
|
73
|
-
this._taskHandler = {
|
|
74
|
-
cancel: function cancel() {
|
|
75
|
-
return clearTimeout(timeoutHandler);
|
|
76
|
-
}
|
|
77
|
-
};
|
|
103
|
+
this._debounced();
|
|
78
104
|
};
|
|
79
105
|
return BatchinateLast;
|
|
80
106
|
}();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batchinate-last.esm.js","sources":["../src/index.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"file":"batchinate-last.esm.js","sources":["../src/index.ts"],"sourcesContent":["import debounce from '@x-oasis/debounce';\n\n/**\n * BatchinateLast - Executes the callback with the last arguments after a delay.\n * If schedule is called multiple times within the delay period, only the last\n * call's arguments will be used when the callback executes.\n */\ntype TaskHandler = {\n cancel: () => void;\n};\n\nclass BatchinateLast {\n readonly _delayMS: number;\n private _callback: (...args: any[]) => void;\n private _debounced: ReturnType<typeof debounce>;\n private _storedArgs: any[] | null = null;\n private _isScheduled = false;\n private _clockTime = 0;\n private _lastTime = 0;\n private _rescheduleHandler: TaskHandler | null = null;\n\n constructor(cb: (...args: any[]) => void, delayMS: number) {\n this._callback = cb;\n this._delayMS = delayMS;\n\n // Helper function to handle execution and potential rescheduling\n const executeAndReschedule = (): void => {\n const savedClockTime = this._clockTime;\n this._isScheduled = false;\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n\n // Check if there were new calls during execution\n // If lastTime was updated (clockTime !== lastTime), reschedule\n if (this._delayMS && savedClockTime !== this._lastTime) {\n const now = Date.now();\n const elapsedTime = now - this._lastTime;\n const timeoutTime = Math.max(this._delayMS - elapsedTime, 0);\n this._clockTime = now;\n\n // Reschedule with remaining time\n const timeoutHandle = setTimeout(() => {\n executeAndReschedule();\n }, timeoutTime);\n this._rescheduleHandler = { cancel: () => clearTimeout(timeoutHandle) };\n this._isScheduled = true;\n }\n };\n\n // Create a debounced function\n // Special behavior: if new calls occur during execution, reschedule\n this._debounced = debounce(executeAndReschedule, delayMS, {\n leading: false,\n trailing: true,\n });\n }\n\n /**\n * Dispose the scheduled task\n * @param options - Configuration options\n * @param options.abort - If true, cancel without executing callback\n */\n dispose(\n options: {\n abort?: boolean;\n } = {\n abort: false,\n }\n ): void {\n const { abort = false } = options;\n if (abort) {\n this._debounced.cancel();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n this._storedArgs = null;\n } else {\n // Execute with current args if any\n if (this._storedArgs !== null) {\n this._debounced.flush();\n }\n }\n }\n\n /**\n * Check if a task is currently scheduled\n */\n inSchedule(): boolean {\n return this._isScheduled || this._rescheduleHandler !== null;\n }\n\n /**\n * Flush the scheduled task immediately\n * @param args - Optional arguments to use instead of stored args\n */\n flush(...args: any[]): void {\n if (args.length > 0) {\n this._storedArgs = args;\n }\n this._debounced.flush();\n if (this._rescheduleHandler) {\n this._rescheduleHandler.cancel();\n this._rescheduleHandler = null;\n }\n this._isScheduled = false;\n }\n\n /**\n * Schedule the callback to execute after delayMS\n * If called multiple times, only the last call's arguments will be used\n * @param args - Arguments to pass to the callback\n */\n schedule(...args: any[]): void {\n this._storedArgs = args;\n const now = Date.now();\n this._lastTime = now;\n\n // Handle zero delay case - execute immediately\n if (!this._delayMS) {\n if (this._storedArgs !== null) {\n this._callback(...this._storedArgs);\n }\n return;\n }\n\n // If already scheduled, just update args and return (don't reset timer)\n if (this._isScheduled) {\n return;\n }\n\n // First call - mark as scheduled and call debounce\n this._isScheduled = true;\n this._clockTime = now;\n this._debounced();\n }\n}\n\nexport default BatchinateLast;\n"],"names":["BatchinateLast","cb","delayMS","_callback","_delayMS","executeAndReschedule","savedClockTime","_this","_clockTime","_isScheduled","_rescheduleHandler","cancel","_storedArgs","apply","_lastTime","now","Date","elapsedTime","timeoutTime","Math","max","timeoutHandle","setTimeout","clearTimeout","_debounced","debounce","leading","trailing","_proto","prototype","dispose","options","abort","_options","_options$abort","flush","inSchedule","args","Array","_len","_key","arguments","length","schedule","_len2","_key2"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
declare class BatchinateLast {
|
|
2
2
|
readonly _delayMS: number;
|
|
3
|
-
private _args;
|
|
4
3
|
private _callback;
|
|
4
|
+
private _debounced;
|
|
5
|
+
private _storedArgs;
|
|
6
|
+
private _isScheduled;
|
|
5
7
|
private _clockTime;
|
|
6
8
|
private _lastTime;
|
|
7
|
-
private
|
|
8
|
-
constructor(cb:
|
|
9
|
+
private _rescheduleHandler;
|
|
10
|
+
constructor(cb: (...args: any[]) => void, delayMS: number);
|
|
9
11
|
dispose(options?: {
|
|
10
|
-
abort
|
|
12
|
+
abort?: boolean;
|
|
11
13
|
}): void;
|
|
12
14
|
inSchedule(): boolean;
|
|
13
15
|
flush(...args: any[]): void;
|
|
14
|
-
handler(): void;
|
|
15
16
|
schedule(...args: any[]): void;
|
|
16
17
|
}
|
|
17
18
|
export default BatchinateLast;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-oasis/batchinate-last",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.38",
|
|
4
4
|
"description": "batchinate-last function",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
"devDependencies": {
|
|
14
14
|
"tsdx": "^0.14.1"
|
|
15
15
|
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@x-oasis/debounce": "0.1.38"
|
|
18
|
+
},
|
|
16
19
|
"scripts": {
|
|
17
20
|
"build": "tsdx build --tsconfig tsconfig.build.json",
|
|
18
21
|
"clean": "rimraf ./dist",
|
package/src/index.ts
CHANGED
|
@@ -1,85 +1,145 @@
|
|
|
1
|
-
|
|
2
|
-
readonly _delayMS: number;
|
|
3
|
-
private _args: Array<any>;
|
|
1
|
+
import debounce from '@x-oasis/debounce';
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
/**
|
|
4
|
+
* BatchinateLast - Executes the callback with the last arguments after a delay.
|
|
5
|
+
* If schedule is called multiple times within the delay period, only the last
|
|
6
|
+
* call's arguments will be used when the callback executes.
|
|
7
|
+
*/
|
|
8
|
+
type TaskHandler = {
|
|
9
|
+
cancel: () => void;
|
|
10
|
+
};
|
|
6
11
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
class BatchinateLast {
|
|
13
|
+
readonly _delayMS: number;
|
|
14
|
+
private _callback: (...args: any[]) => void;
|
|
15
|
+
private _debounced: ReturnType<typeof debounce>;
|
|
16
|
+
private _storedArgs: any[] | null = null;
|
|
17
|
+
private _isScheduled = false;
|
|
18
|
+
private _clockTime = 0;
|
|
19
|
+
private _lastTime = 0;
|
|
20
|
+
private _rescheduleHandler: TaskHandler | null = null;
|
|
12
21
|
|
|
13
|
-
constructor(cb:
|
|
22
|
+
constructor(cb: (...args: any[]) => void, delayMS: number) {
|
|
14
23
|
this._callback = cb;
|
|
15
24
|
this._delayMS = delayMS;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
25
|
+
|
|
26
|
+
// Helper function to handle execution and potential rescheduling
|
|
27
|
+
const executeAndReschedule = (): void => {
|
|
28
|
+
const savedClockTime = this._clockTime;
|
|
29
|
+
this._isScheduled = false;
|
|
30
|
+
if (this._rescheduleHandler) {
|
|
31
|
+
this._rescheduleHandler.cancel();
|
|
32
|
+
this._rescheduleHandler = null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (this._storedArgs !== null) {
|
|
36
|
+
this._callback(...this._storedArgs);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check if there were new calls during execution
|
|
40
|
+
// If lastTime was updated (clockTime !== lastTime), reschedule
|
|
41
|
+
if (this._delayMS && savedClockTime !== this._lastTime) {
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
const elapsedTime = now - this._lastTime;
|
|
44
|
+
const timeoutTime = Math.max(this._delayMS - elapsedTime, 0);
|
|
45
|
+
this._clockTime = now;
|
|
46
|
+
|
|
47
|
+
// Reschedule with remaining time
|
|
48
|
+
const timeoutHandle = setTimeout(() => {
|
|
49
|
+
executeAndReschedule();
|
|
50
|
+
}, timeoutTime);
|
|
51
|
+
this._rescheduleHandler = { cancel: () => clearTimeout(timeoutHandle) };
|
|
52
|
+
this._isScheduled = true;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// Create a debounced function
|
|
57
|
+
// Special behavior: if new calls occur during execution, reschedule
|
|
58
|
+
this._debounced = debounce(executeAndReschedule, delayMS, {
|
|
59
|
+
leading: false,
|
|
60
|
+
trailing: true,
|
|
61
|
+
});
|
|
19
62
|
}
|
|
20
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Dispose the scheduled task
|
|
66
|
+
* @param options - Configuration options
|
|
67
|
+
* @param options.abort - If true, cancel without executing callback
|
|
68
|
+
*/
|
|
21
69
|
dispose(
|
|
22
70
|
options: {
|
|
23
|
-
abort
|
|
71
|
+
abort?: boolean;
|
|
24
72
|
} = {
|
|
25
73
|
abort: false,
|
|
26
74
|
}
|
|
27
|
-
) {
|
|
28
|
-
const { abort } = options;
|
|
29
|
-
if (
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
75
|
+
): void {
|
|
76
|
+
const { abort = false } = options;
|
|
77
|
+
if (abort) {
|
|
78
|
+
this._debounced.cancel();
|
|
79
|
+
if (this._rescheduleHandler) {
|
|
80
|
+
this._rescheduleHandler.cancel();
|
|
81
|
+
this._rescheduleHandler = null;
|
|
82
|
+
}
|
|
83
|
+
this._isScheduled = false;
|
|
84
|
+
this._storedArgs = null;
|
|
85
|
+
} else {
|
|
86
|
+
// Execute with current args if any
|
|
87
|
+
if (this._storedArgs !== null) {
|
|
88
|
+
this._debounced.flush();
|
|
89
|
+
}
|
|
35
90
|
}
|
|
36
91
|
}
|
|
37
92
|
|
|
38
|
-
|
|
39
|
-
|
|
93
|
+
/**
|
|
94
|
+
* Check if a task is currently scheduled
|
|
95
|
+
*/
|
|
96
|
+
inSchedule(): boolean {
|
|
97
|
+
return this._isScheduled || this._rescheduleHandler !== null;
|
|
40
98
|
}
|
|
41
99
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
this.
|
|
49
|
-
this._taskHandler = null;
|
|
100
|
+
/**
|
|
101
|
+
* Flush the scheduled task immediately
|
|
102
|
+
* @param args - Optional arguments to use instead of stored args
|
|
103
|
+
*/
|
|
104
|
+
flush(...args: any[]): void {
|
|
105
|
+
if (args.length > 0) {
|
|
106
|
+
this._storedArgs = args;
|
|
50
107
|
}
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const timeoutTime = Math.max(this._delayMS - elapsedTime, 0);
|
|
56
|
-
this._clockTime = Date.now();
|
|
57
|
-
const timeoutHandler = setTimeout(() => {
|
|
58
|
-
this.handler();
|
|
59
|
-
}, timeoutTime);
|
|
60
|
-
|
|
61
|
-
this._taskHandler = { cancel: () => clearTimeout(timeoutHandler) };
|
|
108
|
+
this._debounced.flush();
|
|
109
|
+
if (this._rescheduleHandler) {
|
|
110
|
+
this._rescheduleHandler.cancel();
|
|
111
|
+
this._rescheduleHandler = null;
|
|
62
112
|
}
|
|
113
|
+
this._isScheduled = false;
|
|
63
114
|
}
|
|
64
115
|
|
|
65
|
-
|
|
66
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Schedule the callback to execute after delayMS
|
|
118
|
+
* If called multiple times, only the last call's arguments will be used
|
|
119
|
+
* @param args - Arguments to pass to the callback
|
|
120
|
+
*/
|
|
121
|
+
schedule(...args: any[]): void {
|
|
122
|
+
this._storedArgs = args;
|
|
67
123
|
const now = Date.now();
|
|
68
124
|
this._lastTime = now;
|
|
69
125
|
|
|
70
|
-
|
|
71
|
-
|
|
126
|
+
// Handle zero delay case - execute immediately
|
|
72
127
|
if (!this._delayMS) {
|
|
73
|
-
this.
|
|
128
|
+
if (this._storedArgs !== null) {
|
|
129
|
+
this._callback(...this._storedArgs);
|
|
130
|
+
}
|
|
74
131
|
return;
|
|
75
132
|
}
|
|
76
133
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
134
|
+
// If already scheduled, just update args and return (don't reset timer)
|
|
135
|
+
if (this._isScheduled) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
81
138
|
|
|
82
|
-
|
|
139
|
+
// First call - mark as scheduled and call debounce
|
|
140
|
+
this._isScheduled = true;
|
|
141
|
+
this._clockTime = now;
|
|
142
|
+
this._debounced();
|
|
83
143
|
}
|
|
84
144
|
}
|
|
85
145
|
|
package/test/test.spec.ts
CHANGED
|
@@ -1,5 +1,249 @@
|
|
|
1
|
-
import { expect, test } from 'vitest';
|
|
1
|
+
import { expect, test, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import BatchinateLast from '../src/index';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
vi.useFakeTimers();
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
vi.restoreAllMocks();
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('BatchinateLast basic functionality - uses last arguments', () => {
|
|
13
|
+
const fn = vi.fn();
|
|
14
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
15
|
+
|
|
16
|
+
batchinator.schedule('First');
|
|
17
|
+
batchinator.schedule('Second');
|
|
18
|
+
batchinator.schedule('Third');
|
|
19
|
+
|
|
20
|
+
expect(fn).not.toHaveBeenCalled();
|
|
21
|
+
|
|
22
|
+
vi.advanceTimersByTime(100);
|
|
23
|
+
|
|
24
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
25
|
+
expect(fn).toHaveBeenCalledWith('Third');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('BatchinateLast flush', () => {
|
|
29
|
+
const fn = vi.fn();
|
|
30
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
31
|
+
|
|
32
|
+
batchinator.schedule('First');
|
|
33
|
+
batchinator.schedule('Second');
|
|
34
|
+
batchinator.flush();
|
|
35
|
+
|
|
36
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
37
|
+
expect(fn).toHaveBeenCalledWith('Second');
|
|
38
|
+
|
|
39
|
+
vi.advanceTimersByTime(100);
|
|
40
|
+
expect(fn).toHaveBeenCalledTimes(1); // Already flushed
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('BatchinateLast flush with new arguments', () => {
|
|
44
|
+
const fn = vi.fn();
|
|
45
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
46
|
+
|
|
47
|
+
batchinator.schedule('First');
|
|
48
|
+
batchinator.flush('Custom');
|
|
49
|
+
|
|
50
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(fn).toHaveBeenCalledWith('Custom');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('BatchinateLast dispose without abort', () => {
|
|
55
|
+
const fn = vi.fn();
|
|
56
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
57
|
+
|
|
58
|
+
batchinator.schedule('First');
|
|
59
|
+
batchinator.schedule('Second');
|
|
60
|
+
batchinator.dispose();
|
|
61
|
+
|
|
62
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
63
|
+
expect(fn).toHaveBeenCalledWith('Second');
|
|
64
|
+
|
|
65
|
+
vi.advanceTimersByTime(100);
|
|
66
|
+
expect(fn).toHaveBeenCalledTimes(1); // Already disposed
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('BatchinateLast dispose with abort', () => {
|
|
70
|
+
const fn = vi.fn();
|
|
71
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
72
|
+
|
|
73
|
+
batchinator.schedule('First');
|
|
74
|
+
batchinator.schedule('Second');
|
|
75
|
+
batchinator.dispose({ abort: true });
|
|
76
|
+
|
|
77
|
+
expect(fn).not.toHaveBeenCalled();
|
|
78
|
+
|
|
79
|
+
vi.advanceTimersByTime(100);
|
|
80
|
+
expect(fn).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('BatchinateLast inSchedule', () => {
|
|
84
|
+
const fn = vi.fn();
|
|
85
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
86
|
+
|
|
87
|
+
expect(batchinator.inSchedule()).toBe(false);
|
|
88
|
+
|
|
89
|
+
batchinator.schedule('First');
|
|
90
|
+
expect(batchinator.inSchedule()).toBe(true);
|
|
91
|
+
|
|
92
|
+
batchinator.flush();
|
|
93
|
+
expect(batchinator.inSchedule()).toBe(false);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test('BatchinateLast inSchedule after dispose', () => {
|
|
97
|
+
const fn = vi.fn();
|
|
98
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
99
|
+
|
|
100
|
+
batchinator.schedule('First');
|
|
101
|
+
expect(batchinator.inSchedule()).toBe(true);
|
|
102
|
+
|
|
103
|
+
batchinator.dispose({ abort: true });
|
|
104
|
+
expect(batchinator.inSchedule()).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
test('BatchinateLast with zero delay', () => {
|
|
108
|
+
const fn = vi.fn();
|
|
109
|
+
const batchinator = new BatchinateLast(fn, 0);
|
|
110
|
+
|
|
111
|
+
batchinator.schedule('First');
|
|
112
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
113
|
+
expect(fn).toHaveBeenCalledWith('First');
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test('BatchinateLast preserves this context', () => {
|
|
117
|
+
const obj = {
|
|
118
|
+
value: 42,
|
|
119
|
+
fn: function (this: any, arg: number) {
|
|
120
|
+
return this.value + arg;
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const batchinator = new BatchinateLast(obj.fn, 100);
|
|
125
|
+
batchinator.schedule(10);
|
|
126
|
+
|
|
127
|
+
vi.advanceTimersByTime(100);
|
|
128
|
+
// Function executes with correct context
|
|
129
|
+
expect(obj.value).toBe(42);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('BatchinateLast multiple rapid calls', () => {
|
|
133
|
+
const fn = vi.fn();
|
|
134
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < 10; i++) {
|
|
137
|
+
batchinator.schedule(i);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
expect(fn).not.toHaveBeenCalled();
|
|
141
|
+
|
|
142
|
+
vi.advanceTimersByTime(100);
|
|
143
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
144
|
+
expect(fn).toHaveBeenCalledWith(9); // Last call
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('BatchinateLast with multiple arguments', () => {
|
|
148
|
+
const fn = vi.fn();
|
|
149
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
150
|
+
|
|
151
|
+
batchinator.schedule(1, 'a', true);
|
|
152
|
+
batchinator.schedule(2, 'b', false);
|
|
153
|
+
batchinator.schedule(3, 'c', true);
|
|
154
|
+
|
|
155
|
+
vi.advanceTimersByTime(100);
|
|
156
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
157
|
+
expect(fn).toHaveBeenCalledWith(3, 'c', true);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test('BatchinateLast reschedules if new calls during execution', () => {
|
|
161
|
+
const fn = vi.fn();
|
|
162
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
163
|
+
|
|
164
|
+
batchinator.schedule('First');
|
|
165
|
+
|
|
166
|
+
// Advance time to trigger execution
|
|
167
|
+
vi.advanceTimersByTime(50);
|
|
168
|
+
batchinator.schedule('Second'); // New call during wait period
|
|
169
|
+
|
|
170
|
+
vi.advanceTimersByTime(50);
|
|
171
|
+
// Handler executes with 'First', then checks for new calls
|
|
172
|
+
expect(fn).toHaveBeenCalled();
|
|
173
|
+
|
|
174
|
+
// If there were new calls, it should reschedule
|
|
175
|
+
vi.advanceTimersByTime(100);
|
|
176
|
+
// Should execute with 'Second'
|
|
177
|
+
expect(fn.mock.calls.length).toBeGreaterThan(1);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('BatchinateLast schedule after flush', () => {
|
|
181
|
+
const fn = vi.fn();
|
|
182
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
183
|
+
|
|
184
|
+
batchinator.schedule('First');
|
|
185
|
+
batchinator.flush();
|
|
186
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
187
|
+
|
|
188
|
+
batchinator.schedule('Second');
|
|
189
|
+
vi.advanceTimersByTime(100);
|
|
190
|
+
expect(fn).toHaveBeenCalledTimes(2);
|
|
191
|
+
expect(fn).toHaveBeenCalledWith('Second');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('BatchinateLast schedule after dispose', () => {
|
|
195
|
+
const fn = vi.fn();
|
|
196
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
197
|
+
|
|
198
|
+
batchinator.schedule('First');
|
|
199
|
+
batchinator.dispose({ abort: true });
|
|
200
|
+
expect(fn).not.toHaveBeenCalled();
|
|
201
|
+
|
|
202
|
+
batchinator.schedule('Second');
|
|
203
|
+
vi.advanceTimersByTime(100);
|
|
204
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
205
|
+
expect(fn).toHaveBeenCalledWith('Second');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test('BatchinateLast continuous scheduling', () => {
|
|
209
|
+
const fn = vi.fn();
|
|
210
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
211
|
+
|
|
212
|
+
batchinator.schedule('First');
|
|
213
|
+
vi.advanceTimersByTime(50);
|
|
214
|
+
batchinator.schedule('Second');
|
|
215
|
+
vi.advanceTimersByTime(50);
|
|
216
|
+
batchinator.schedule('Third');
|
|
217
|
+
|
|
218
|
+
// Should eventually execute with 'Third'
|
|
219
|
+
vi.advanceTimersByTime(100);
|
|
220
|
+
expect(fn).toHaveBeenCalled();
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
test('BatchinateLast flush empty schedule', () => {
|
|
224
|
+
const fn = vi.fn();
|
|
225
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
226
|
+
|
|
227
|
+
// Flush without scheduling
|
|
228
|
+
batchinator.flush();
|
|
229
|
+
expect(fn).not.toHaveBeenCalled();
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
test('BatchinateLast dispose empty schedule', () => {
|
|
233
|
+
const fn = vi.fn();
|
|
234
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
235
|
+
|
|
236
|
+
// Dispose without scheduling
|
|
237
|
+
batchinator.dispose();
|
|
238
|
+
expect(fn).not.toHaveBeenCalled();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test('BatchinateLast flush with empty args after scheduling', () => {
|
|
242
|
+
const fn = vi.fn();
|
|
243
|
+
const batchinator = new BatchinateLast(fn, 100);
|
|
244
|
+
|
|
245
|
+
batchinator.schedule('First');
|
|
246
|
+
batchinator.flush(); // No new args provided
|
|
247
|
+
expect(fn).toHaveBeenCalledTimes(1);
|
|
248
|
+
expect(fn).toHaveBeenCalledWith('First');
|
|
5
249
|
});
|