##// END OF EJS Templates
removed debounce(...).applyAsync
cin -
r161:be122e264286 default
parent child
Show More
@@ -1,574 +1,565
1 import { ICancellable, Constructor, IDestroyable, ICancellation, IRemovable } from "./interfaces";
1 import { ICancellable, Constructor, IDestroyable, ICancellation, IRemovable } from "./interfaces";
2
2
3 let _nextOid = 0;
3 let _nextOid = 0;
4 const _oid = typeof Symbol === "function" ?
4 const _oid = typeof Symbol === "function" ?
5 Symbol("__implab__oid__") :
5 Symbol("__implab__oid__") :
6 "__implab__oid__";
6 "__implab__oid__";
7
7
8 function _noop() { }
8 function _noop() { }
9
9
10 export function oid(instance: null | undefined): undefined;
10 export function oid(instance: null | undefined): undefined;
11 export function oid(instance: NonNullable<any>): string;
11 export function oid(instance: NonNullable<any>): string;
12 export function oid(instance: any): string | undefined {
12 export function oid(instance: any): string | undefined {
13 if (isNull(instance))
13 if (isNull(instance))
14 return undefined;
14 return undefined;
15
15
16 if (_oid in instance)
16 if (_oid in instance)
17 return instance[_oid];
17 return instance[_oid];
18 else
18 else
19 return (instance[_oid] = "oid_" + (++_nextOid));
19 return (instance[_oid] = "oid_" + (++_nextOid));
20 }
20 }
21
21
22 const cancellationNone: ICancellation = {
22 const cancellationNone: ICancellation = {
23 isSupported(): boolean {
23 isSupported(): boolean {
24 return false;
24 return false;
25 },
25 },
26
26
27 throwIfRequested(): void {
27 throwIfRequested(): void {
28 },
28 },
29
29
30 isRequested(): boolean {
30 isRequested(): boolean {
31 return false;
31 return false;
32 },
32 },
33
33
34 register(_cb: (e: any) => void): IDestroyable {
34 register(_cb: (e: any) => void): IDestroyable {
35 return destroyed;
35 return destroyed;
36 }
36 }
37 };
37 };
38
38
39 export function keys<T>(arg: T): (Extract<keyof T, string>)[] {
39 export function keys<T>(arg: T): (Extract<keyof T, string>)[] {
40 return isObject(arg) && arg ? Object.keys(arg) as (Extract<keyof T, string>)[] : [];
40 return isObject(arg) && arg ? Object.keys(arg) as (Extract<keyof T, string>)[] : [];
41 }
41 }
42
42
43 export function isKeyof<T>(k: string, target: T): k is Extract<keyof T, string> {
43 export function isKeyof<T>(k: string, target: T): k is Extract<keyof T, string> {
44 return target && typeof target === "object" && k in target;
44 return target && typeof target === "object" && k in target;
45 }
45 }
46
46
47 export function argumentNotNull(arg: any, name: string) {
47 export function argumentNotNull(arg: any, name: string) {
48 if (arg === null || arg === undefined)
48 if (arg === null || arg === undefined)
49 throw new Error("The argument " + name + " can't be null or undefined");
49 throw new Error("The argument " + name + " can't be null or undefined");
50 }
50 }
51
51
52 export function argumentNotEmptyString(arg: any, name: string) {
52 export function argumentNotEmptyString(arg: any, name: string) {
53 if (typeof (arg) !== "string" || !arg.length)
53 if (typeof (arg) !== "string" || !arg.length)
54 throw new Error("The argument '" + name + "' must be a not empty string");
54 throw new Error("The argument '" + name + "' must be a not empty string");
55 }
55 }
56
56
57 export function argumentNotEmptyArray(arg: any, name: string) {
57 export function argumentNotEmptyArray(arg: any, name: string) {
58 if (!(arg instanceof Array) || !arg.length)
58 if (!(arg instanceof Array) || !arg.length)
59 throw new Error("The argument '" + name + "' must be a not empty array");
59 throw new Error("The argument '" + name + "' must be a not empty array");
60 }
60 }
61
61
62 export function argumentOfType(arg: any, type: Constructor<{}>, name: string) {
62 export function argumentOfType(arg: any, type: Constructor<{}>, name: string) {
63 if (!(arg instanceof type))
63 if (!(arg instanceof type))
64 throw new Error("The argument '" + name + "' type doesn't match");
64 throw new Error("The argument '" + name + "' type doesn't match");
65 }
65 }
66
66
67 export function isNull(val: any): val is null | undefined {
67 export function isNull(val: any): val is null | undefined {
68 return (val === null || val === undefined);
68 return (val === null || val === undefined);
69 }
69 }
70
70
71 export type primitive = symbol | string | number | boolean | undefined | null;
71 export type primitive = symbol | string | number | boolean | undefined | null;
72
72
73 export function isPrimitive(val: any): val is primitive {
73 export function isPrimitive(val: any): val is primitive {
74 return (val === null || val === undefined || typeof (val) === "string" ||
74 return (val === null || val === undefined || typeof (val) === "string" ||
75 typeof (val) === "number" || typeof (val) === "boolean");
75 typeof (val) === "number" || typeof (val) === "boolean");
76 }
76 }
77
77
78 export function isObject<T>(value: T): value is Exclude<T & object, primitive> {
78 export function isObject<T>(value: T): value is Exclude<T & object, primitive> {
79 return !!(value && typeof value === "object");
79 return !!(value && typeof value === "object");
80 }
80 }
81
81
82 export function isInteger(val: any): val is number {
82 export function isInteger(val: any): val is number {
83 return parseInt(val, 10) === val;
83 return parseInt(val, 10) === val;
84 }
84 }
85
85
86 export function isNumber(val: any): val is number {
86 export function isNumber(val: any): val is number {
87 return parseFloat(val) === val;
87 return parseFloat(val) === val;
88 }
88 }
89
89
90 export function isString(val: any): val is string {
90 export function isString(val: any): val is string {
91 return typeof (val) === "string";
91 return typeof (val) === "string";
92 }
92 }
93
93
94 export function isPromise<T = any>(val: any): val is PromiseLike<T> {
94 export function isPromise<T = any>(val: any): val is PromiseLike<T> {
95 return !!(val && typeof val.then === "function");
95 return !!(val && typeof val.then === "function");
96 }
96 }
97
97
98 export function isCancellable(val: any): val is ICancellable {
98 export function isCancellable(val: any): val is ICancellable {
99 return !!(val && typeof val.cancel === "function");
99 return !!(val && typeof val.cancel === "function");
100 }
100 }
101
101
102 export function isNullOrEmptyString(val: any): val is ("" | null | undefined) {
102 export function isNullOrEmptyString(val: any): val is ("" | null | undefined) {
103 return (val === null || val === undefined ||
103 return (val === null || val === undefined ||
104 ((typeof (val) === "string" || val instanceof String) && val.length === 0));
104 ((typeof (val) === "string" || val instanceof String) && val.length === 0));
105 }
105 }
106
106
107 export function isNotEmptyArray<T = any>(arg: any): arg is T[] {
107 export function isNotEmptyArray<T = any>(arg: any): arg is T[] {
108 return (arg instanceof Array && arg.length > 0);
108 return (arg instanceof Array && arg.length > 0);
109 }
109 }
110
110
111 function _isStrictMode(this: any) {
111 function _isStrictMode(this: any) {
112 return !this;
112 return !this;
113 }
113 }
114
114
115 function _getNonStrictGlobal(this: any) {
115 function _getNonStrictGlobal(this: any) {
116 return this;
116 return this;
117 }
117 }
118
118
119 export function getGlobal() {
119 export function getGlobal() {
120 // in es3 we can't use indirect call to eval, since it will
120 // in es3 we can't use indirect call to eval, since it will
121 // be executed in the current call context.
121 // be executed in the current call context.
122 if (!_isStrictMode()) {
122 if (!_isStrictMode()) {
123 return _getNonStrictGlobal();
123 return _getNonStrictGlobal();
124 } else {
124 } else {
125 // tslint:disable-next-line:no-eval
125 // tslint:disable-next-line:no-eval
126 return eval.call(null, "this");
126 return eval.call(null, "this");
127 }
127 }
128 }
128 }
129
129
130 export function get(member: string, context?: object) {
130 export function get(member: string, context?: object) {
131 argumentNotEmptyString(member, "member");
131 argumentNotEmptyString(member, "member");
132 let that = context || getGlobal();
132 let that = context || getGlobal();
133 const parts = member.split(".");
133 const parts = member.split(".");
134 for (const m of parts) {
134 for (const m of parts) {
135 if (!m)
135 if (!m)
136 continue;
136 continue;
137 if (isNull(that = that[m]))
137 if (isNull(that = that[m]))
138 break;
138 break;
139 }
139 }
140 return that;
140 return that;
141 }
141 }
142
142
143 /**
143 /**
144 * ВыполняСт ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива, останавливаСтся, ΠΊΠΎΠ³Π΄Π°
144 * ВыполняСт ΠΌΠ΅Ρ‚ΠΎΠ΄ для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта массива, останавливаСтся, ΠΊΠΎΠ³Π΄Π°
145 * Π»ΠΈΠ±ΠΎ достигнут ΠΊΠΎΠ½Π΅Ρ† массива, Π»ΠΈΠ±ΠΎ функция <c>cb</c> Π²Π΅Ρ€Π½ΡƒΠ»Π°
145 * Π»ΠΈΠ±ΠΎ достигнут ΠΊΠΎΠ½Π΅Ρ† массива, Π»ΠΈΠ±ΠΎ функция <c>cb</c> Π²Π΅Ρ€Π½ΡƒΠ»Π°
146 * Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
146 * Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.
147 *
147 *
148 * @param {Array | Object} obj массив элСмСнтов для просмотра
148 * @param {Array | Object} obj массив элСмСнтов для просмотра
149 * @param {Function} cb функция, вызываСмая для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта
149 * @param {Function} cb функция, вызываСмая для ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ элСмСнта
150 * @param {Object} thisArg Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² качСствС
150 * @param {Object} thisArg Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ΠΎ Π² качСствС
151 * <c>this</c> Π² <c>cb</c>.
151 * <c>this</c> Π² <c>cb</c>.
152 * @returns {void}
152 * @returns {void}
153 */
153 */
154 export function each<T>(obj: T, cb: <X extends Extract<keyof T, string>>(v: NonNullable<T[X]>, k: X) => void): void;
154 export function each<T>(obj: T, cb: <X extends Extract<keyof T, string>>(v: NonNullable<T[X]>, k: X) => void): void;
155 export function each<T>(array: T[], cb: (v: T, i: number) => void): void;
155 export function each<T>(array: T[], cb: (v: T, i: number) => void): void;
156 export function each(obj: any, cb: any, thisArg?: any): any;
156 export function each(obj: any, cb: any, thisArg?: any): any;
157 export function each(obj: any, cb: any, thisArg?: any) {
157 export function each(obj: any, cb: any, thisArg?: any) {
158 argumentNotNull(cb, "cb");
158 argumentNotNull(cb, "cb");
159 if (obj instanceof Array) {
159 if (obj instanceof Array) {
160 let v: any;
160 let v: any;
161 for (let i = 0; i < obj.length; i++) {
161 for (let i = 0; i < obj.length; i++) {
162 v = obj[i];
162 v = obj[i];
163 if (v !== undefined)
163 if (v !== undefined)
164 cb.call(thisArg, v, i);
164 cb.call(thisArg, v, i);
165 }
165 }
166 } else {
166 } else {
167 Object.keys(obj).forEach(k => obj[k] !== undefined && cb.call(thisArg, obj[k], k));
167 Object.keys(obj).forEach(k => obj[k] !== undefined && cb.call(thisArg, obj[k], k));
168 }
168 }
169 }
169 }
170
170
171 /** Copies property values from a source object to the destination and returns
171 /** Copies property values from a source object to the destination and returns
172 * the destination object.
172 * the destination object.
173 *
173 *
174 * @param dest The destination object into which properties from the source
174 * @param dest The destination object into which properties from the source
175 * object will be copied.
175 * object will be copied.
176 * @param source The source of values which will be copied to the destination
176 * @param source The source of values which will be copied to the destination
177 * object.
177 * object.
178 * @param template An optional parameter specifies which properties should be
178 * @param template An optional parameter specifies which properties should be
179 * copied from the source and how to map them to the destination. If the
179 * copied from the source and how to map them to the destination. If the
180 * template is an array it contains the list of property names to copy from the
180 * template is an array it contains the list of property names to copy from the
181 * source to the destination. In case of object the templates contains the map
181 * source to the destination. In case of object the templates contains the map
182 * where keys are property names in the source and the values are property
182 * where keys are property names in the source and the values are property
183 * names in the destination object. If the template isn't specified then the
183 * names in the destination object. If the template isn't specified then the
184 * own properties of the source are entirely copied to the destination.
184 * own properties of the source are entirely copied to the destination.
185 *
185 *
186 */
186 */
187 export function mixin<T extends object, S extends object>(dest: T, source: S, template?: (keyof S)[]): T & S;
187 export function mixin<T extends object, S extends object>(dest: T, source: S, template?: (keyof S)[]): T & S;
188 export function mixin<T extends object, S extends object, R extends object = T>(dest: T, source: S, template: { [p in keyof S]?: keyof R; }): T & R;
188 export function mixin<T extends object, S extends object, R extends object = T>(dest: T, source: S, template: { [p in keyof S]?: keyof R; }): T & R;
189 export function mixin<T extends object, S extends object>(dest: T, source: S, template?: any): any {
189 export function mixin<T extends object, S extends object>(dest: T, source: S, template?: any): any {
190 argumentNotNull(dest, "dest");
190 argumentNotNull(dest, "dest");
191 const _res: any = dest as any;
191 const _res: any = dest as any;
192
192
193 if (isPrimitive(source))
193 if (isPrimitive(source))
194 return _res;
194 return _res;
195
195
196 if (template instanceof Array) {
196 if (template instanceof Array) {
197 template.forEach(p => {
197 template.forEach(p => {
198 if (isKeyof(p, source))
198 if (isKeyof(p, source))
199 _res[p] = source[p];
199 _res[p] = source[p];
200 });
200 });
201 } else if (template) {
201 } else if (template) {
202 keys(source).forEach(p => {
202 keys(source).forEach(p => {
203 if (isKeyof(p, template))
203 if (isKeyof(p, template))
204 _res[template[p]] = source[p];
204 _res[template[p]] = source[p];
205 });
205 });
206 } else {
206 } else {
207 keys(source).forEach(p => _res[p] = source[p]);
207 keys(source).forEach(p => _res[p] = source[p]);
208 }
208 }
209
209
210 return _res;
210 return _res;
211 }
211 }
212
212
213 /** Wraps the specified function to emulate an asynchronous execution.
213 /** Wraps the specified function to emulate an asynchronous execution.
214 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
214 * @param{Object} thisArg [Optional] Object which will be passed as 'this' to the function.
215 * @param{Function|String} fn [Required] Function wich will be wrapped.
215 * @param{Function|String} fn [Required] Function wich will be wrapped.
216 */
216 */
217 export function async<T, F extends (...args: any[]) => T | PromiseLike<T>>(
217 export function async<T, F extends (...args: any[]) => T | PromiseLike<T>>(
218 fn: F,
218 fn: F,
219 thisArg?: ThisParameterType<F>
219 thisArg?: ThisParameterType<F>
220 ): (...args: Parameters<F>) => PromiseLike<T>;
220 ): (...args: Parameters<F>) => PromiseLike<T>;
221 export function async<T, M extends string, O extends { [m in M]?: (...args: any[]) => T | PromiseLike<T> }>(
221 export function async<T, M extends string, O extends { [m in M]?: (...args: any[]) => T | PromiseLike<T> }>(
222 fn: M,
222 fn: M,
223 thisArg: O
223 thisArg: O
224 ): (...args: Parameters<NonNullable<O[M]>>) => PromiseLike<T>;
224 ): (...args: Parameters<NonNullable<O[M]>>) => PromiseLike<T>;
225 export function async(_fn: any, thisArg: any): (...args: any[]) => PromiseLike<any> {
225 export function async(_fn: any, thisArg: any): (...args: any[]) => PromiseLike<any> {
226 let fn = _fn;
226 let fn = _fn;
227
227
228 if (arguments.length === 2 && !(fn instanceof Function))
228 if (arguments.length === 2 && !(fn instanceof Function))
229 fn = thisArg[fn];
229 fn = thisArg[fn];
230
230
231 if (fn == null)
231 if (fn == null)
232 throw new Error("The function must be specified");
232 throw new Error("The function must be specified");
233
233
234 function wrapresult(x: any, e?: any): PromiseLike<any> {
234 function wrapresult(x: any, e?: any): PromiseLike<any> {
235 if (e) {
235 if (e) {
236 return {
236 return {
237 then(cb, eb) {
237 then(cb, eb) {
238 try {
238 try {
239 return eb ? wrapresult(eb(e)) : this;
239 return eb ? wrapresult(eb(e)) : this;
240 } catch (e2) {
240 } catch (e2) {
241 return wrapresult(null, e2);
241 return wrapresult(null, e2);
242 }
242 }
243 }
243 }
244 };
244 };
245 } else {
245 } else {
246 if (x && x.then)
246 if (x && x.then)
247 return x;
247 return x;
248 return {
248 return {
249 then(cb) {
249 then(cb) {
250 try {
250 try {
251 return cb ? wrapresult(cb(x)) : this;
251 return cb ? wrapresult(cb(x)) : this;
252 } catch (e2) {
252 } catch (e2) {
253 return wrapresult(e2);
253 return wrapresult(e2);
254 }
254 }
255 }
255 }
256 };
256 };
257 }
257 }
258 }
258 }
259
259
260 return (...args) => {
260 return (...args) => {
261 try {
261 try {
262 return wrapresult(fn.apply(thisArg, args));
262 return wrapresult(fn.apply(thisArg, args));
263 } catch (e) {
263 } catch (e) {
264 return wrapresult(null, e);
264 return wrapresult(null, e);
265 }
265 }
266 };
266 };
267 }
267 }
268
268
269 export function delegate<T extends object, F extends (this: T, ...args: any[]) => any>(
269 export function delegate<T extends object, F extends (this: T, ...args: any[]) => any>(
270 target: T,
270 target: T,
271 method: F
271 method: F
272 ): OmitThisParameter<F>;
272 ): OmitThisParameter<F>;
273 export function delegate<M extends string, T extends { [m in M]?: (...args: any[]) => any; }>(
273 export function delegate<M extends string, T extends { [m in M]?: (...args: any[]) => any; }>(
274 target: T,
274 target: T,
275 method: M
275 method: M
276 ): OmitThisParameter<T[M]>;
276 ): OmitThisParameter<T[M]>;
277 export function delegate(target: any, _method: any): (...args: any[]) => any {
277 export function delegate(target: any, _method: any): (...args: any[]) => any {
278 let method: any;
278 let method: any;
279 if (!(_method instanceof Function)) {
279 if (!(_method instanceof Function)) {
280 argumentNotNull(target, "target");
280 argumentNotNull(target, "target");
281 method = target[_method];
281 method = target[_method];
282 if (!(method instanceof Function))
282 if (!(method instanceof Function))
283 throw new Error("'method' argument must be a Function or a method name");
283 throw new Error("'method' argument must be a Function or a method name");
284 } else {
284 } else {
285 method = _method;
285 method = _method;
286 }
286 }
287
287
288 return (...args) => {
288 return (...args) => {
289 return method.apply(target, args);
289 return method.apply(target, args);
290 };
290 };
291 }
291 }
292
292
293 /** Returns promise which will be resolved after the specified amount of time.
293 /** Returns promise which will be resolved after the specified amount of time.
294 *
294 *
295 * @param timeMs The delay before the promise will be resolved in milliseconds.
295 * @param timeMs The delay before the promise will be resolved in milliseconds.
296 * @param ct Optional. A cancellation token for the operation.
296 * @param ct Optional. A cancellation token for the operation.
297 */
297 */
298 export function delay(timeMs: number, ct = cancellationNone) {
298 export function delay(timeMs: number, ct = cancellationNone) {
299 ct.throwIfRequested();
299 ct.throwIfRequested();
300 return new Promise<void>((resolve, reject) => {
300 return new Promise<void>((resolve, reject) => {
301 const h = ct.register(e => {
301 const h = ct.register(e => {
302 clearTimeout(id);
302 clearTimeout(id);
303 reject(e);
303 reject(e);
304 // we don't nedd to unregister h, since ct is already disposed
304 // we don't nedd to unregister h, since ct is already disposed
305 });
305 });
306 const id = setTimeout(() => {
306 const id = setTimeout(() => {
307 h.destroy();
307 h.destroy();
308 resolve();
308 resolve();
309 }, timeMs);
309 }, timeMs);
310
310
311 });
311 });
312 }
312 }
313
313
314 export function debounce<T extends any[], R, This>(func: (this: This, ...args: T) => R | PromiseLike<R>, wait: number) {
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;
315 let cancel: (e?: any) => void = _noop;
316
316
317 const fn = function executedFunction(this: This, ...args: T) {
317 const fn = function executedFunction(this: This, ...args: T) {
318 return new Promise<R>((resolve, reject) => {
318 return new Promise<R>((resolve, reject) => {
319
319
320 // used to cleanup currently allocated resources
320 // used to cleanup currently allocated resources
321 const _cleanup = () => {
321 const _cleanup = () => {
322 cancel = _noop;
322 cancel = _noop;
323 clearTimeout(handle);
323 clearTimeout(handle);
324 };
324 };
325
325
326 // used in case of cancellation of the current operation
326 // used in case of cancellation of the current operation
327 const _cancel = (e: any) => {
327 const _cancel = (e: any) => {
328 _cleanup();
328 _cleanup();
329 reject(e);
329 reject(e);
330 };
330 };
331
331
332 // performs actual work
332 // performs actual work
333 const _later = () => {
333 const _later = () => {
334 _cleanup();
334 _cleanup();
335 resolve(func.apply(this, args));
335 resolve(func.apply(this, args));
336 };
336 };
337
337
338 // cancel previously queued operation
338 // cancel previously queued operation
339 if (cancel !== _noop)
339 if (cancel !== _noop)
340 cancel(new Error("Operation cancelled due to debouncing"));
340 cancel(new Error("Operation cancelled due to debouncing"));
341 cancel = _cancel;
341 cancel = _cancel;
342
342
343 const handle = setTimeout(_later, wait);
343 const handle = setTimeout(_later, wait);
344 });
344 });
345 };
345 };
346
346
347 fn.cancel = (e?: any) => cancel(e);
347 fn.cancel = (e?: any) => cancel(e);
348
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;
349 return fn;
359 }
350 }
360
351
361 /** Returns resolved promise, awaiting this method will cause the asynchronous
352 /** Returns resolved promise, awaiting this method will cause the asynchronous
362 * completion of the rest of the code.
353 * completion of the rest of the code.
363 */
354 */
364 export function fork() {
355 export function fork() {
365 return Promise.resolve();
356 return Promise.resolve();
366 }
357 }
367
358
368 /** Always throws Error, can be used as a stub for the methods which should be
359 /** Always throws Error, can be used as a stub for the methods which should be
369 * assigned later and are required to be not null.
360 * assigned later and are required to be not null.
370 */
361 */
371 export function notImplemented(): never {
362 export function notImplemented(): never {
372 throw new Error("Not implemented");
363 throw new Error("Not implemented");
373 }
364 }
374 /**
365 /**
375 * Iterates over the specified array of items and calls the callback `cb`, if
366 * Iterates over the specified array of items and calls the callback `cb`, if
376 * the result of the callback is a promise the next item from the array will be
367 * the result of the callback is a promise the next item from the array will be
377 * proceeded after the promise is resolved.
368 * proceeded after the promise is resolved.
378 *
369 *
379 */
370 */
380 export function pmap<T, T2>(
371 export function pmap<T, T2>(
381 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
372 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
382 cb: (item: T, i: number) => T2 | PromiseLike<T2>
373 cb: (item: T, i: number) => T2 | PromiseLike<T2>
383 ): T2[] | PromiseLike<T2[]> {
374 ): T2[] | PromiseLike<T2[]> {
384 argumentNotNull(cb, "cb");
375 argumentNotNull(cb, "cb");
385
376
386 if (isPromise(items)) {
377 if (isPromise(items)) {
387 return items.then(data => pmap(data, cb));
378 return items.then(data => pmap(data, cb));
388 } else {
379 } else {
389
380
390 if (isNull(items) || !items.length)
381 if (isNull(items) || !items.length)
391 return [];
382 return [];
392
383
393 let i = 0;
384 let i = 0;
394 const result = new Array<T2>();
385 const result = new Array<T2>();
395
386
396 const next = (): any => {
387 const next = (): any => {
397 while (i < items.length) {
388 while (i < items.length) {
398 const r = cb(items[i], i);
389 const r = cb(items[i], i);
399 const ri = i;
390 const ri = i;
400 i++;
391 i++;
401 if (isPromise(r)) {
392 if (isPromise(r)) {
402 return r.then(x => {
393 return r.then(x => {
403 result[ri] = x;
394 result[ri] = x;
404 return next();
395 return next();
405 });
396 });
406 } else {
397 } else {
407 result[ri] = r;
398 result[ri] = r;
408 }
399 }
409 }
400 }
410 return result;
401 return result;
411 };
402 };
412
403
413 return next();
404 return next();
414 }
405 }
415 }
406 }
416
407
417 export function pfor<T>(
408 export function pfor<T>(
418 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
409 items: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
419 cb: (item: T, i: number) => any
410 cb: (item: T, i: number) => any
420 ): void | PromiseLike<void> {
411 ): void | PromiseLike<void> {
421 argumentNotNull(cb, "cb");
412 argumentNotNull(cb, "cb");
422
413
423 if (isPromise(items)) {
414 if (isPromise(items)) {
424 return items.then(data => pfor(data, cb));
415 return items.then(data => pfor(data, cb));
425 } else {
416 } else {
426 if (isNull(items) || !items.length)
417 if (isNull(items) || !items.length)
427 return;
418 return;
428
419
429 let i = 0;
420 let i = 0;
430
421
431 const next = (): any => {
422 const next = (): any => {
432 while (i < items.length) {
423 while (i < items.length) {
433 const r = cb(items[i], i);
424 const r = cb(items[i], i);
434 i++;
425 i++;
435 if (isPromise(r))
426 if (isPromise(r))
436 return r.then(next);
427 return r.then(next);
437 }
428 }
438 };
429 };
439
430
440 return next();
431 return next();
441 }
432 }
442 }
433 }
443
434
444 export function first<T>(sequence: ArrayLike<T>): T;
435 export function first<T>(sequence: ArrayLike<T>): T;
445 export function first<T>(sequence: PromiseLike<ArrayLike<T>>): PromiseLike<T>;
436 export function first<T>(sequence: PromiseLike<ArrayLike<T>>): PromiseLike<T>;
446 export function first<T>(
437 export function first<T>(
447 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
438 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
448 cb?: (x: T) => void,
439 cb?: (x: T) => void,
449 err?: (x: Error) => void
440 err?: (x: Error) => void
450 ): void;
441 ): void;
451 /**
442 /**
452 * Π’Ρ‹Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΈΠ»ΠΈ обСщания, Ссли Π²
443 * Π’Ρ‹Π±ΠΈΡ€Π°Π΅Ρ‚ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт ΠΈΠ· ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΈΠ»ΠΈ обСщания, Ссли Π²
453 * качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ массив.
444 * качСствС ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, ΠΎΠ½ΠΎ Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ массив.
454 *
445 *
455 * @param {Function} cb ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π΅ΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ
446 * @param {Function} cb ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°, Π΅ΠΌΡƒ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠ΅Ρ€Π΅Π΄Π°Π½ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ
456 * элСмСнт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² случаС успСха
447 * элСмСнт ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Π² случаС успСха
457 * @param {Function} err ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, Ссли массив пустой, Π»ΠΈΠ±ΠΎ
448 * @param {Function} err ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ, Ссли массив пустой, Π»ΠΈΠ±ΠΎ
458 * нС массив
449 * нС массив
459 *
450 *
460 * @remarks Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½ΠΈ cb Π½ΠΈ err, Ρ‚ΠΎΠ³Π΄Π° функция Π²Π΅Ρ€Π½Π΅Ρ‚ Π»ΠΈΠ±ΠΎ
451 * @remarks Если Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Ρ‹ Π½ΠΈ cb Π½ΠΈ err, Ρ‚ΠΎΠ³Π΄Π° функция Π²Π΅Ρ€Π½Π΅Ρ‚ Π»ΠΈΠ±ΠΎ
461 * ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт.
452 * ΠΎΠ±Π΅Ρ‰Π°Π½ΠΈΠ΅, Π»ΠΈΠ±ΠΎ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ элСмСнт.
462 * @async
453 * @async
463 */
454 */
464 export function first<T>(
455 export function first<T>(
465 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
456 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
466 cb?: (x: T) => void,
457 cb?: (x: T) => void,
467 err?: (x: Error) => void
458 err?: (x: Error) => void
468 ) {
459 ) {
469 if (isPromise(sequence)) {
460 if (isPromise(sequence)) {
470 return sequence.then(res => first(res, cb as any /* force to pass undefined cb */, err));
461 return sequence.then(res => first(res, cb as any /* force to pass undefined cb */, err));
471 } else if (sequence && "length" in sequence) {
462 } else if (sequence && "length" in sequence) {
472 if (sequence.length === 0) {
463 if (sequence.length === 0) {
473 if (err)
464 if (err)
474 return err(new Error("The sequence is empty"));
465 return err(new Error("The sequence is empty"));
475 else
466 else
476 throw new Error("The sequence is empty");
467 throw new Error("The sequence is empty");
477 } else if (cb) {
468 } else if (cb) {
478 return cb(sequence[0]);
469 return cb(sequence[0]);
479 } else {
470 } else {
480 return sequence[0];
471 return sequence[0];
481 }
472 }
482 } else {
473 } else {
483 if (err)
474 if (err)
484 return err(new Error("The sequence is required"));
475 return err(new Error("The sequence is required"));
485 else
476 else
486 throw new Error("The sequence is required");
477 throw new Error("The sequence is required");
487 }
478 }
488 }
479 }
489
480
490 export function firstWhere<T>(
481 export function firstWhere<T>(
491 sequence: ArrayLike<T>,
482 sequence: ArrayLike<T>,
492 predicate: (x: T) => boolean
483 predicate: (x: T) => boolean
493 ): T;
484 ): T;
494 export function firstWhere<T>(
485 export function firstWhere<T>(
495 sequence: PromiseLike<ArrayLike<T>>,
486 sequence: PromiseLike<ArrayLike<T>>,
496 predicate: (x: T) => boolean
487 predicate: (x: T) => boolean
497 ): PromiseLike<T>;
488 ): PromiseLike<T>;
498 export function firstWhere<T>(
489 export function firstWhere<T>(
499 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
490 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
500 predicate: (x: T) => boolean,
491 predicate: (x: T) => boolean,
501 cb: (x: T) => void,
492 cb: (x: T) => void,
502 err?: (x: Error) => void
493 err?: (x: Error) => void
503 ): void;
494 ): void;
504
495
505 export function firstWhere<T>(
496 export function firstWhere<T>(
506 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
497 sequence: ArrayLike<T> | PromiseLike<ArrayLike<T>>,
507 predicate?: (x: T) => boolean,
498 predicate?: (x: T) => boolean,
508 cb?: (x: T) => any,
499 cb?: (x: T) => any,
509 err?: (x: Error) => any
500 err?: (x: Error) => any
510 ) {
501 ) {
511 if (isPromise(sequence)) {
502 if (isPromise(sequence)) {
512 return sequence.then(res => firstWhere(
503 return sequence.then(res => firstWhere(
513 res,
504 res,
514 predicate as any /* force to pass undefined predicate */,
505 predicate as any /* force to pass undefined predicate */,
515 cb as any /* force to pass undefined cb */,
506 cb as any /* force to pass undefined cb */,
516 err)
507 err)
517 );
508 );
518 } else if (sequence && "length" in sequence) {
509 } else if (sequence && "length" in sequence) {
519 if (sequence.length === 0) {
510 if (sequence.length === 0) {
520 if (err)
511 if (err)
521 err(new Error("The sequence is empty"));
512 err(new Error("The sequence is empty"));
522 else
513 else
523 throw new Error("The sequence is empty");
514 throw new Error("The sequence is empty");
524 } else {
515 } else {
525 if (!predicate) {
516 if (!predicate) {
526 return cb ? cb(sequence[0]) && void (0) : sequence[0];
517 return cb ? cb(sequence[0]) && void (0) : sequence[0];
527 } else {
518 } else {
528 for (let i = 0; i < sequence.length; i++) {
519 for (let i = 0; i < sequence.length; i++) {
529 const v = sequence[i];
520 const v = sequence[i];
530 if (predicate(v))
521 if (predicate(v))
531 return cb ? cb(v) : v;
522 return cb ? cb(v) : v;
532 }
523 }
533 if (err)
524 if (err)
534 err(new Error("The sequence doesn't contain matching items"));
525 err(new Error("The sequence doesn't contain matching items"));
535 else
526 else
536 throw new Error("The sequence doesn't contain matching items");
527 throw new Error("The sequence doesn't contain matching items");
537 }
528 }
538 }
529 }
539 } else {
530 } else {
540 if (err)
531 if (err)
541 err(new Error("The sequence is required"));
532 err(new Error("The sequence is required"));
542 else
533 else
543 throw new Error("The sequence is required");
534 throw new Error("The sequence is required");
544 }
535 }
545 }
536 }
546
537
547 export function isDestroyable(d: any): d is IDestroyable {
538 export function isDestroyable(d: any): d is IDestroyable {
548 return !!(d && typeof d.destroy === "function");
539 return !!(d && typeof d.destroy === "function");
549 }
540 }
550
541
551 export function isRemovable(value: any): value is IRemovable {
542 export function isRemovable(value: any): value is IRemovable {
552 return !!(value && typeof value.remove === "function");
543 return !!(value && typeof value.remove === "function");
553 }
544 }
554
545
555 export function destroy(d: any) {
546 export function destroy(d: any) {
556 if (isDestroyable(d))
547 if (isDestroyable(d))
557 d.destroy();
548 d.destroy();
558 }
549 }
559
550
560 /**
551 /**
561 * Used to mark that the async operation isn't awaited intentionally.
552 * Used to mark that the async operation isn't awaited intentionally.
562 * @param p The promise which represents the async operation.
553 * @param p The promise which represents the async operation.
563 */
554 */
564 export function nowait(p: Promise<any>) {
555 export function nowait(p: Promise<any>) {
565 }
556 }
566
557
567 /** represents already destroyed object.
558 /** represents already destroyed object.
568 */
559 */
569 export const destroyed = {
560 export const destroyed = {
570 /** Calling to this method doesn't affect anything, noop.
561 /** Calling to this method doesn't affect anything, noop.
571 */
562 */
572 destroy() {
563 destroy() {
573 }
564 }
574 };
565 };
@@ -1,156 +1,156
1 import { Cancellation } from "../Cancellation";
1 import { Cancellation } from "../Cancellation";
2 import { ICancellation } from "../interfaces";
2 import { ICancellation } from "../interfaces";
3 import { first, isPromise, firstWhere, delay, nowait, notImplemented, debounce, fork } from "../safe";
3 import { first, isPromise, firstWhere, delay, nowait, notImplemented, debounce, fork } from "../safe";
4 import { test } from "./TestTraits";
4 import { test } from "./TestTraits";
5
5
6 test("await delay test", async t => {
6 test("await delay test", async t => {
7 // schedule delay
7 // schedule delay
8 let resolved = false;
8 let resolved = false;
9 let res = delay(0).then(() => resolved = true);
9 let res = delay(0).then(() => resolved = true);
10
10
11 t.false(resolved, "the delay should be async");
11 t.false(resolved, "the delay should be async");
12
12
13 await res;
13 await res;
14 t.pass("await delay");
14 t.pass("await delay");
15
15
16 // create cancellation token
16 // create cancellation token
17 let cancel: (e?: any) => void = notImplemented;
17 let cancel: (e?: any) => void = notImplemented;
18 const ct = new Cancellation(c => cancel = c);
18 const ct = new Cancellation(c => cancel = c);
19
19
20 // schedule delay
20 // schedule delay
21 resolved = false;
21 resolved = false;
22 res = delay(0, ct).then(() => resolved = true);
22 res = delay(0, ct).then(() => resolved = true);
23
23
24 t.false(resolved, "created delay with ct");
24 t.false(resolved, "created delay with ct");
25
25
26 // cancel
26 // cancel
27 cancel();
27 cancel();
28
28
29 try {
29 try {
30 await res;
30 await res;
31 t.fail("the delay should fail when it is cancelled");
31 t.fail("the delay should fail when it is cancelled");
32 } catch {
32 } catch {
33 t.pass("the delay is cancelled");
33 t.pass("the delay is cancelled");
34 }
34 }
35
35
36 t.throws(() => {
36 t.throws(() => {
37 // try schedule delay after the cancellation is requested
37 // try schedule delay after the cancellation is requested
38 nowait(delay(0, ct));
38 nowait(delay(0, ct));
39 }, "Should throw if cancelled before start");
39 }, "Should throw if cancelled before start");
40 });
40 });
41
41
42 test("sequemce test", async t => {
42 test("sequemce test", async t => {
43 const sequence = ["a", "b", "c"];
43 const sequence = ["a", "b", "c"];
44 const empty: string[] = [];
44 const empty: string[] = [];
45
45
46 // synchronous tests
46 // synchronous tests
47 t.equals(first(sequence), "a", "Should return the first element");
47 t.equals(first(sequence), "a", "Should return the first element");
48 t.equals(firstWhere(sequence, x => x === "b"), "b", "Should get the second element");
48 t.equals(firstWhere(sequence, x => x === "b"), "b", "Should get the second element");
49
49
50 let v: string | undefined;
50 let v: string | undefined;
51 let e: Error | undefined;
51 let e: Error | undefined;
52 first(sequence, x => v = x);
52 first(sequence, x => v = x);
53 t.equal(v, "a", "The callback should be called for the first element");
53 t.equal(v, "a", "The callback should be called for the first element");
54 firstWhere(sequence, x => x === "b", x => v = x);
54 firstWhere(sequence, x => x === "b", x => v = x);
55 t.equal(v, "b", "The callback should be called for the second element");
55 t.equal(v, "b", "The callback should be called for the second element");
56
56
57 t.throws(() => {
57 t.throws(() => {
58 first(empty);
58 first(empty);
59 }, "Should throw when the sequence is empty");
59 }, "Should throw when the sequence is empty");
60
60
61 t.throws(() => {
61 t.throws(() => {
62 firstWhere(empty, x => x === "b");
62 firstWhere(empty, x => x === "b");
63 }, "Should throw when the sequence is empty");
63 }, "Should throw when the sequence is empty");
64
64
65 t.throws(() => {
65 t.throws(() => {
66 first(empty, x => v = x);
66 first(empty, x => v = x);
67 }, "Should throw when the sequence is empty");
67 }, "Should throw when the sequence is empty");
68
68
69 t.throws(() => {
69 t.throws(() => {
70 firstWhere(empty, x => x === "b", x => v = x);
70 firstWhere(empty, x => x === "b", x => v = x);
71 }, "Should throw when the sequence is empty");
71 }, "Should throw when the sequence is empty");
72
72
73 t.throws(() => {
73 t.throws(() => {
74 firstWhere(sequence, x => x === "z");
74 firstWhere(sequence, x => x === "z");
75 }, "Should throw when the element isn't found");
75 }, "Should throw when the element isn't found");
76
76
77 t.throws(() => {
77 t.throws(() => {
78 firstWhere(sequence, x => x === "z", x => v = x);
78 firstWhere(sequence, x => x === "z", x => v = x);
79 }, "Should throw when the element isn't found");
79 }, "Should throw when the element isn't found");
80
80
81 first(empty, undefined, x => e = x);
81 first(empty, undefined, x => e = x);
82 t.true(e, "The errorback should be called for the empty sequence");
82 t.true(e, "The errorback should be called for the empty sequence");
83
83
84 // async tests
84 // async tests
85 const asyncSequence = Promise.resolve(sequence);
85 const asyncSequence = Promise.resolve(sequence);
86 const asyncEmptySequence = Promise.resolve(empty);
86 const asyncEmptySequence = Promise.resolve(empty);
87
87
88 const promise = first(asyncSequence);
88 const promise = first(asyncSequence);
89 t.true(isPromise(promise), "Should return promise");
89 t.true(isPromise(promise), "Should return promise");
90
90
91 v = await promise;
91 v = await promise;
92 t.equal(v, "a", "Should return the first element");
92 t.equal(v, "a", "Should return the first element");
93
93
94 v = await new Promise(resolve => first(asyncSequence, resolve));
94 v = await new Promise(resolve => first(asyncSequence, resolve));
95 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");
96 });
96 });
97
97
98 test("debounce tests", async (t, trace) => {
98 test("debounce tests", async (t, trace) => {
99 let count = 0;
99 let count = 0;
100 let rejected = 0;
100 let rejected = 0;
101 function increment(step: number = 1) {
101 function increment(step: number = 1) {
102 count += step;
102 count += step;
103 return count;
103 return count;
104 }
104 }
105
105
106 const f = debounce(increment, 100);
106 const f = debounce(increment, 100);
107 f().then(undefined, () => rejected++);
107 f().then(undefined, () => rejected++);
108 f().then(undefined, () => rejected++);
108 f().then(undefined, () => rejected++);
109
109
110 await f(1);
110 await f(1);
111
111
112 t.equal(rejected, 2, "Previous operations should be rejected");
112 t.equal(rejected, 2, "Previous operations should be rejected");
113 t.equal(count, 1, "The operation should run once");
113 t.equal(count, 1, "The operation should run once");
114
114
115 const acc = debounce(
115 const acc = debounce(
116 (...values: number[]) => count = values.reduce((a, v) => v + a, count),
116 (...values: number[]) => count = values.reduce((a, v) => v + a, count),
117 100
117 100
118 );
118 );
119
119
120 acc(1, 2, 3).catch(() => { });
120 acc(1, 2, 3).catch(() => { });
121 const result = acc(1, 2, 3);
121 const result = acc(1, 2, 3);
122 acc.cancel();
122 acc.cancel();
123
123
124 try {
124 try {
125 await result;
125 await result;
126 t.notOk("fn.cancel() should make current operation to throw an exception");
126 t.notOk("fn.cancel() should make current operation to throw an exception");
127 } catch {
127 } catch {
128 t.ok("fn.cancel() should make current operation to throw an exception");
128 t.ok("fn.cancel() should make current operation to throw an exception");
129 }
129 }
130
130
131 t.equal(count, 1, "fn.cancel() The operation should not run");
131 t.equal(count, 1, "fn.cancel() The operation should not run");
132
132
133 acc.cancel();
133 acc.cancel();
134 await acc(1, 2);
134 await acc(1, 2);
135 t.equal(count, 4, "The variable arguments list shoud be handled correctly");
135 t.equal(count, 4, "The variable arguments list shoud be handled correctly");
136
136
137 // create cancellation token
137 // create cancellation token
138 let cancel: (e?: any) => void = notImplemented;
138 let cancel: (e?: any) => void = notImplemented;
139 const ct = new Cancellation(c => cancel = c);
139 const ct = new Cancellation(c => cancel = c);
140
140
141 const d = debounce(async (ct2: ICancellation = Cancellation.none) => {
141 const d = debounce(async () => {
142 ct2.throwIfRequested();
142 ct.throwIfRequested();
143 trace.debug("do async increment");
143 trace.debug("do async increment");
144 await fork();
144 await fork();
145 count++;
145 count++;
146 return count;
146 return count;
147 }, 0);
147 }, 0);
148
148
149 const p = d.applyAsync(null, [ct], ct).then(undefined, () => rejected++);
149 const p = d().then(undefined, () => rejected++);
150 cancel();
150 cancel();
151 await p;
151 await p;
152
152
153 t.equal(count, 4, "Cancellation token should prevent the function execution");
153 t.equal(count, 4, "Cancellation token should prevent the function execution");
154 t.equal(rejected, 3, "Cancellation token should reject operation");
154 t.equal(rejected, 3, "Cancellation token should reject operation");
155
155
156 });
156 });
General Comments 0
You need to be logged in to leave comments. Login now