| @@ -1260,9 +1260,9 | |||||
| 1260 | } |
|
1260 | } | |
| 1261 | }, |
|
1261 | }, | |
| 1262 | "typescript": { |
|
1262 | "typescript": { | |
| 1263 |
"version": " |
|
1263 | "version": "4.1.5", | |
| 1264 |
"resolved": "https://registry.npmjs.org/typescript/-/typescript- |
|
1264 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.5.tgz", | |
| 1265 | "integrity": "sha512-unoCll1+l+YK4i4F8f22TaNVPRHcD9PA3yCuZ8g5e0qGqlVlJ/8FSateOLLSagn+Yg5+ZwuPkL8LFUc0Jcvksg==", |
|
1265 | "integrity": "sha512-6OSu9PTIzmn9TCDiovULTnET6BgXtDYL4Gg4szY+cGsc3JP1dQL8qvE8kShTRx1NIw4Q9IBHlwODjkjWEtMUyA==", | |
| 1266 | "dev": true |
|
1266 | "dev": true | |
| 1267 | }, |
|
1267 | }, | |
| 1268 | "uri-js": { |
|
1268 | "uri-js": { | |
| @@ -27,7 +27,7 | |||||
| 27 | "dojo-typings": "^1.11.9", |
|
27 | "dojo-typings": "^1.11.9", | |
| 28 | "requirejs": "latest", |
|
28 | "requirejs": "latest", | |
| 29 | "tape": "~4.11.0", |
|
29 | "tape": "~4.11.0", | |
| 30 |
"typescript": "~ |
|
30 | "typescript": "~4.1.5", | |
| 31 | "eslint": "6.1.0", |
|
31 | "eslint": "6.1.0", | |
| 32 | "tslint": "5.18.0" |
|
32 | "tslint": "5.18.0" | |
| 33 | } |
|
33 | } | |
| @@ -5,6 +5,8 const _oid = typeof Symbol === "function | |||||
| 5 | Symbol("__implab__oid__") : |
|
5 | Symbol("__implab__oid__") : | |
| 6 | "__implab__oid__"; |
|
6 | "__implab__oid__"; | |
| 7 |
|
7 | |||
|
|
8 | function _noop() { } | |||
|
|
9 | ||||
| 8 | export function oid(instance: null | undefined): undefined; |
|
10 | export function oid(instance: null | undefined): undefined; | |
| 9 | export function oid(instance: NonNullable<any>): string; |
|
11 | export function oid(instance: NonNullable<any>): string; | |
| 10 | export function oid(instance: any): string | undefined { |
|
12 | export function oid(instance: any): string | undefined { | |
| @@ -288,9 +290,14 export function delegate(target: any, _m | |||||
| 288 | }; |
|
290 | }; | |
| 289 | } |
|
291 | } | |
| 290 |
|
292 | |||
|
|
293 | /** Returns promise which will be resolved after the specified amount of time. | |||
|
|
294 | * | |||
|
|
295 | * @param timeMs The delay before the promise will be resolved in milliseconds. | |||
|
|
296 | * @param ct Optional. A cancellation token for the operation. | |||
|
|
297 | */ | |||
| 291 | export function delay(timeMs: number, ct = cancellationNone) { |
|
298 | export function delay(timeMs: number, ct = cancellationNone) { | |
| 292 | ct.throwIfRequested(); |
|
299 | ct.throwIfRequested(); | |
| 293 | return new Promise((resolve, reject) => { |
|
300 | return new Promise<void>((resolve, reject) => { | |
| 294 | const h = ct.register(e => { |
|
301 | const h = ct.register(e => { | |
| 295 | clearTimeout(id); |
|
302 | clearTimeout(id); | |
| 296 | reject(e); |
|
303 | reject(e); | |
| @@ -304,6 +311,53 export function delay(timeMs: number, ct | |||||
| 304 | }); |
|
311 | }); | |
| 305 | } |
|
312 | } | |
| 306 |
|
313 | |||
|
|
314 | export function debounce<T extends any[], R, This>(func: (this: This, ...args: T) => R | PromiseLike<R>, wait: number) { | |||
|
|
315 | let cancel: (e?: any) => void = _noop; | |||
|
|
316 | ||||
|
|
317 | const fn = function executedFunction(this: This, ...args: T) { | |||
|
|
318 | return new Promise<R>((resolve, reject) => { | |||
|
|
319 | ||||
|
|
320 | // used to cleanup currently allocated resources | |||
|
|
321 | const _cleanup = () => { | |||
|
|
322 | cancel = _noop; | |||
|
|
323 | clearTimeout(handle); | |||
|
|
324 | }; | |||
|
|
325 | ||||
|
|
326 | // used in case of cancellation of the current operation | |||
|
|
327 | const _cancel = (e: any) => { | |||
|
|
328 | _cleanup(); | |||
|
|
329 | reject(e); | |||
|
|
330 | }; | |||
|
|
331 | ||||
|
|
332 | // performs actual work | |||
|
|
333 | const _later = () => { | |||
|
|
334 | _cleanup(); | |||
|
|
335 | resolve(func.apply(this, args)); | |||
|
|
336 | }; | |||
|
|
337 | ||||
|
|
338 | // cancel previously queued operation | |||
|
|
339 | if (cancel !== _noop) | |||
|
|
340 | cancel(new Error("Operation cancelled due to debouncing")); | |||
|
|
341 | cancel = _cancel; | |||
|
|
342 | ||||
|
|
343 | const handle = setTimeout(_later, wait); | |||
|
|
344 | }); | |||
|
|
345 | }; | |||
|
|
346 | ||||
|
|
347 | fn.cancel = (e?: any) => cancel(e); | |||
|
|
348 | ||||
|
|
349 | fn.applyAsync = async (thisArg: This, args: T, ct: ICancellation) => { | |||
|
|
350 | const h = ct.register(cancel); | |||
|
|
351 | try { | |||
|
|
352 | await fn.apply(thisArg, args); | |||
|
|
353 | } finally { | |||
|
|
354 | h.destroy(); | |||
|
|
355 | } | |||
|
|
356 | }; | |||
|
|
357 | ||||
|
|
358 | return fn; | |||
|
|
359 | } | |||
|
|
360 | ||||
| 307 | /** Returns resolved promise, awaiting this method will cause the asynchronous |
|
361 | /** Returns resolved promise, awaiting this method will cause the asynchronous | |
| 308 | * completion of the rest of the code. |
|
362 | * completion of the rest of the code. | |
| 309 | */ |
|
363 | */ | |
| @@ -1,5 +1,6 | |||||
| 1 | import { Cancellation } from "../Cancellation"; |
|
1 | import { Cancellation } from "../Cancellation"; | |
| 2 | import { first, isPromise, firstWhere, delay, nowait, notImplemented } from "../safe"; |
|
2 | import { ICancellation } from "../interfaces"; | |
|
|
3 | import { first, isPromise, firstWhere, delay, nowait, notImplemented, debounce, fork } from "../safe"; | |||
| 3 | import { test } from "./TestTraits"; |
|
4 | import { test } from "./TestTraits"; | |
| 4 |
|
5 | |||
| 5 | test("await delay test", async t => { |
|
6 | test("await delay test", async t => { | |
| @@ -93,3 +94,63 test("sequemce test", async t => { | |||||
| 93 | v = await new Promise(resolve => first(asyncSequence, resolve)); |
|
94 | v = await new Promise(resolve => first(asyncSequence, resolve)); | |
| 94 | t.equal(v, "a", "The callback should be called for the first element"); |
|
95 | t.equal(v, "a", "The callback should be called for the first element"); | |
| 95 | }); |
|
96 | }); | |
|
|
97 | ||||
|
|
98 | test("debounce tests", async (t, trace) => { | |||
|
|
99 | let count = 0; | |||
|
|
100 | let rejected = 0; | |||
|
|
101 | function increment(step: number = 1) { | |||
|
|
102 | count += step; | |||
|
|
103 | return count; | |||
|
|
104 | } | |||
|
|
105 | ||||
|
|
106 | const f = debounce(increment, 100); | |||
|
|
107 | f().then(undefined, () => rejected++); | |||
|
|
108 | f().then(undefined, () => rejected++); | |||
|
|
109 | ||||
|
|
110 | await f(1); | |||
|
|
111 | ||||
|
|
112 | t.equal(rejected, 2, "Previous operations should be rejected"); | |||
|
|
113 | t.equal(count, 1, "The operation should run once"); | |||
|
|
114 | ||||
|
|
115 | const acc = debounce( | |||
|
|
116 | (...values: number[]) => count = values.reduce((a, v) => v + a, count), | |||
|
|
117 | 100 | |||
|
|
118 | ); | |||
|
|
119 | ||||
|
|
120 | acc(1, 2, 3).catch(() => { }); | |||
|
|
121 | const result = acc(1, 2, 3); | |||
|
|
122 | acc.cancel(); | |||
|
|
123 | ||||
|
|
124 | try { | |||
|
|
125 | await result; | |||
|
|
126 | t.notOk("fn.cancel() should make current operation to throw an exception"); | |||
|
|
127 | } catch { | |||
|
|
128 | t.ok("fn.cancel() should make current operation to throw an exception"); | |||
|
|
129 | } | |||
|
|
130 | ||||
|
|
131 | t.equal(count, 1, "fn.cancel() The operation should not run"); | |||
|
|
132 | ||||
|
|
133 | acc.cancel(); | |||
|
|
134 | await acc(1, 2); | |||
|
|
135 | t.equal(count, 4, "The variable arguments list shoud be handled correctly"); | |||
|
|
136 | ||||
|
|
137 | // create cancellation token | |||
|
|
138 | let cancel: (e?: any) => void = notImplemented; | |||
|
|
139 | const ct = new Cancellation(c => cancel = c); | |||
|
|
140 | ||||
|
|
141 | const d = debounce(async (ct2: ICancellation = Cancellation.none) => { | |||
|
|
142 | ct2.throwIfRequested(); | |||
|
|
143 | trace.debug("do async increment"); | |||
|
|
144 | await fork(); | |||
|
|
145 | count++; | |||
|
|
146 | return count; | |||
|
|
147 | }, 0); | |||
|
|
148 | ||||
|
|
149 | const p = d.applyAsync(null, [ct], ct).then(undefined, () => rejected++); | |||
|
|
150 | cancel(); | |||
|
|
151 | await p; | |||
|
|
152 | ||||
|
|
153 | t.equal(count, 4, "Cancellation token should prevent the function execution"); | |||
|
|
154 | t.equal(rejected, 3, "Cancellation token should reject operation"); | |||
|
|
155 | ||||
|
|
156 | }); | |||
General Comments 0
You need to be logged in to leave comments.
Login now
