@superutils/promise 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -117,7 +117,7 @@ while (!appReady) {
117
117
  }
118
118
  ```
119
119
 
120
- #### `PromisE.delay(duration, callback)`: execute after delay
120
+ #### `PromisE.delay(duration, callback, asRejected)`: execute after delay
121
121
 
122
122
  Creates a promise that executes a function after a specified duration and returns the value the function returns.
123
123
 
@@ -126,10 +126,13 @@ If callback returns undefined, default value will be the duration.
126
126
  ```typescript
127
127
  import PromisE from '@superutils/promise'
128
128
 
129
- const callback = () => {
130
- /* do stuff here */
129
+ const func = async () => {
130
+ console.log('Waiting for app initialization or something else to be ready')
131
+ // wait 3 seconds before proceeding
132
+ await PromisE.delay(3000)
133
+ console.log('App ready')
131
134
  }
132
- await PromisE.delay(100, callback)
135
+ func()
133
136
  ```
134
137
 
135
138
  <div id="deferred"></div>
@@ -138,32 +141,48 @@ await PromisE.delay(100, callback)
138
141
 
139
142
  Create a function that debounces or throttles promise-returning function calls. This is useful for scenarios like auto-saving user input or preventing multiple rapid API calls.
140
143
 
141
- ```typescript
142
- import PromisE, { ResolveIgnored } from '@superutils/promise'
144
+ #### Debounce example:
143
145
 
144
- // Create a deferred function that waits 300ms after the last call
145
- const deferredSave = PromisE.deferred({
146
- defer: 300,
147
- /** ignored promises will resolve with `undefined` */
148
- resolveIgnored: ResolveIgnored.WITH_UNDEFINED,
146
+ ```typescript
147
+ const example = async (options = {}) => {
148
+ const df = PromisE.deferred({
149
+ delayMs: 100,
150
+ resolveIgnored: ResolveIgnored.NEVER, // never resolve ignored calls
151
+ ...options,
152
+ })
153
+ df(() => PromisE.delay(500)).then(console.log)
154
+ df(() => PromisE.delay(1000)).then(console.log)
155
+ df(() => PromisE.delay(5000)).then(console.log)
156
+ // delay 2 seconds and invoke df() again
157
+ await PromisE.delay(2000)
158
+ df(() => PromisE.delay(200)).then(console.log)
159
+ }
160
+ example({ ignoreStale: false, throttle: false })
161
+ // `200` and `1000` will be printed in the console
162
+ example({ ignoreStale: true, throttle: false })
163
+ // `200` will be printed in the console
164
+ ```
149
165
 
150
- /** ignored promises will NEVER be resolved/rejected
151
- * USE WITH CAUTION!
152
- */
153
- resolveIgnored: ResolveIgnored.NEVER,
166
+ #### Throttle example:
154
167
 
155
- // ignored promises will resolve with the result of the last call
156
- resolveIgnored: ResolveIgnored.WITH_LAST, // (default)
157
- })
158
-
159
- // Simulate rapid calls
160
- deferredSave(() => api.save({ text: 'first' }))
161
- deferredSave(() => api.save({ text: 'second' }))
162
- // Only the 3rd call is executed.
163
- // But all of them are resolved with the result of the 3rd call when `resolveIgnored` is `ResolveIgnored.WITH_LAST`
164
- deferredSave(() => api.save({ text: 'third' })).then(response =>
165
- console.log('Saved!', response),
166
- )
168
+ ```typescript
169
+ const example = async (options = {}) => {
170
+ const df = PromisE.deferred({
171
+ delayMs: 100,
172
+ resolveIgnored: ResolveIgnored.NEVER, // never resolve ignored calls
173
+ ...options,
174
+ })
175
+ df(() => PromisE.delay(5000)).then(console.log)
176
+ df(() => PromisE.delay(500)).then(console.log)
177
+ df(() => PromisE.delay(1000)).then(console.log)
178
+ // delay 2 seconds and invoke df() again
179
+ await PromisE.delay(2000)
180
+ df(() => PromisE.delay(200)).then(console.log)
181
+ }
182
+ example({ ignoreStale: true, throttle: true })
183
+ // `200` will be printed in the console
184
+ example({ ignoreStale: false, throttle: true })
185
+ // `200` and `5000` will be printed in the console
167
186
  ```
168
187
 
169
188
  <div id="deferredCallback"></div>
package/dist/index.d.ts CHANGED
@@ -92,6 +92,7 @@ type DeferredAsyncOptions<ThisArg = unknown, DelayMs extends number = number> =
92
92
  * Default: `100` (or what is set in `PromisE.deferred.defaults.delayMs`)
93
93
  */
94
94
  delayMs?: 0 | PositiveNumber<DelayMs>;
95
+ ignoreStale?: boolean;
95
96
  /** Callback invoked whenever promise/function throws error */
96
97
  onError?: (this: ThisArg, err: unknown) => ValueOrPromise<unknown>;
97
98
  /**
package/dist/index.js CHANGED
@@ -176,6 +176,7 @@ var ResolveIgnored = /* @__PURE__ */ ((ResolveIgnored2) => {
176
176
 
177
177
  // src/deferred.ts
178
178
  function deferred(options = {}) {
179
+ let sequence = 0;
179
180
  options = objCopy(
180
181
  deferred.defaults,
181
182
  options,
@@ -198,6 +199,24 @@ function deferred(options = {}) {
198
199
  onIgnore = onIgnore == null ? void 0 : onIgnore.bind(thisArg);
199
200
  onResult = onResult == null ? void 0 : onResult.bind(thisArg);
200
201
  }
202
+ const handleIgnore = (items, prevQItem2) => {
203
+ for (const [iId, iItem] of items) {
204
+ queue.delete(iId);
205
+ if (iItem === void 0 || iItem.started) continue;
206
+ onIgnore && fallbackIfFails2(onIgnore, [iItem.getPromise], 0);
207
+ switch (resolveIgnored) {
208
+ case "WITH_UNDEFINED" /* WITH_UNDEFINED */:
209
+ iItem.resolve(void 0);
210
+ break;
211
+ case "WITH_LAST" /* WITH_LAST */:
212
+ prevQItem2 == null ? void 0 : prevQItem2.then(iItem.resolve, iItem.reject);
213
+ break;
214
+ case "NEVER" /* NEVER */:
215
+ break;
216
+ }
217
+ }
218
+ if (!queue.size) sequence = 0;
219
+ };
201
220
  const handleRemaining = (currentId) => {
202
221
  const _prevQItem = prevQItem;
203
222
  prevQItem = null;
@@ -215,30 +234,19 @@ function deferred(options = {}) {
215
234
  } else if (!throttle && options.leading) {
216
235
  items = items.slice(0, -1);
217
236
  }
218
- for (const [iId, iItem] of items) {
219
- !iItem.completed && queue.delete(iId);
220
- if (iItem === void 0 || iItem.started || iItem.completed)
221
- continue;
222
- iItem.completed = true;
223
- onIgnore && fallbackIfFails2(onIgnore, [iItem.getPromise], 0);
224
- switch (resolveIgnored) {
225
- case "WITH_UNDEFINED" /* WITH_UNDEFINED */:
226
- iItem.resolve(void 0);
227
- break;
228
- case "WITH_LAST" /* WITH_LAST */:
229
- _prevQItem == null ? void 0 : _prevQItem.then(iItem.resolve, iItem.reject);
230
- break;
231
- case "NEVER" /* NEVER */:
232
- break;
233
- }
234
- }
237
+ handleIgnore(items, _prevQItem);
235
238
  };
239
+ let prevSeq = 0;
236
240
  const executeItem = async (id, qItem) => {
237
- if (!id || !(qItem == null ? void 0 : qItem.pending) || qItem.completed) return;
241
+ var _a;
238
242
  qItem.started = true;
243
+ const _prevQItem = prevQItem;
239
244
  prevQItem = qItem;
245
+ prevSeq = (_a = prevQItem == null ? void 0 : prevQItem.sequence) != null ? _a : 0;
240
246
  try {
241
247
  const result = await PromisEBase_default.try(qItem.getPromise);
248
+ const ignore = !isSequential && options.ignoreStale && prevSeq > qItem.sequence;
249
+ if (ignore) return handleIgnore([[id, qItem]], _prevQItem);
242
250
  qItem.resolve(result);
243
251
  onResult && fallbackIfFails2(onResult, [result], void 0);
244
252
  } catch (err) {
@@ -257,7 +265,6 @@ function deferred(options = {}) {
257
265
  break;
258
266
  }
259
267
  }
260
- qItem.completed = true;
261
268
  handleRemaining(id);
262
269
  };
263
270
  const handleItem = isSequential ? executeItem : (throttle ? throttledCore : deferredCore)(
@@ -270,6 +277,7 @@ function deferred(options = {}) {
270
277
  const qItem = new PromisEBase_default();
271
278
  qItem.getPromise = isFn2(promise) ? promise : () => promise;
272
279
  qItem.started = false;
280
+ qItem.sequence = ++sequence;
273
281
  queue.set(id, qItem);
274
282
  if (!prevQItem || !isSequential) handleItem(id, qItem);
275
283
  return qItem;
package/package.json CHANGED
@@ -43,5 +43,5 @@
43
43
  "sideEffects": false,
44
44
  "type": "module",
45
45
  "types": "dist/index.d.ts",
46
- "version": "1.1.0"
46
+ "version": "1.1.2"
47
47
  }