Add every() and delay() methods back
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import test from "ava";
|
||||
import { expect } from "chai";
|
||||
import { EventEmitter } from "events";
|
||||
import { once, sleep } from "./utils";
|
||||
import { once, sleep, delay, every } from "./utils";
|
||||
|
||||
const TimingErrorMarginMs = 50;
|
||||
|
||||
@@ -14,6 +14,16 @@ test("sleep() resolves after the specified delay in milliseconds", async t => {
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("delay() resolves a value after the specified delay in milliseconds", async t => {
|
||||
const before = Date.now();
|
||||
const value = await delay("abc", 200);
|
||||
const after = Date.now();
|
||||
|
||||
expect(value).equal("abc");
|
||||
expect(after - before).gte(200);
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("once() resolves only after the specified event is emitted", async t => {
|
||||
const emitter = new EventEmitter();
|
||||
const before = Date.now();
|
||||
@@ -23,7 +33,48 @@ test("once() resolves only after the specified event is emitted", async t => {
|
||||
const result = await once(emitter, "done");
|
||||
const after = Date.now();
|
||||
|
||||
expect(result).to.equal("some-result");
|
||||
expect(result).equal("some-result");
|
||||
expect(after - before).gte(200);
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("every() resolves to true when the predicate holds true for all resolved values", async t => {
|
||||
const before = Date.now();
|
||||
const result = await every(
|
||||
[Promise.resolve("a"), Promise.resolve("b"), delay("c", 200)],
|
||||
() => true,
|
||||
);
|
||||
const after = Date.now();
|
||||
expect(result).equal(true);
|
||||
expect(after - before).gte(200);
|
||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("every() resolves to false as soon as the predicate does not hold for some resolved value", async t => {
|
||||
const before = Date.now();
|
||||
const result = await every(
|
||||
[Promise.resolve("a"), Promise.resolve("bb"), delay("c", 200)],
|
||||
(value: string) => value.length === 1,
|
||||
);
|
||||
const after = Date.now();
|
||||
expect(result).equal(false);
|
||||
expect(after - before).lt(200);
|
||||
expect(after - before).closeTo(0, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
test("every() rejects with the reason as soon as any of the promises rejects", async t => {
|
||||
const before = Date.now();
|
||||
await t.throwsAsync(() =>
|
||||
every(
|
||||
[
|
||||
Promise.resolve("a"),
|
||||
Promise.reject(new Error("Expected")),
|
||||
delay("c", 200),
|
||||
],
|
||||
() => true,
|
||||
),
|
||||
);
|
||||
const after = Date.now();
|
||||
expect(after - before).lt(200);
|
||||
expect(after - before).closeTo(0, TimingErrorMarginMs);
|
||||
});
|
||||
|
||||
63
src/utils.ts
63
src/utils.ts
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Resolve after the given delay in milliseconds
|
||||
*
|
||||
* @param ms - The number of milliseconds to wait
|
||||
* @param ms The number of milliseconds to wait
|
||||
*/
|
||||
export function sleep(ms: number) {
|
||||
return new Promise(resolve => {
|
||||
@@ -9,11 +9,23 @@ export function sleep(ms: number) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a value after the given delay in milliseconds
|
||||
*
|
||||
* @param value Value to resolve
|
||||
* @param ms Number of milliseconds to wait
|
||||
*/
|
||||
export function delay<T>(value: T, ms: number): Promise<T> {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => resolve(value), ms);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve once the given event emitter emits the specified event
|
||||
*
|
||||
* @param emitter - The event emitter to watch
|
||||
* @param event - The event to watch
|
||||
* @param emitter Event emitter to watch
|
||||
* @param event Event to watch
|
||||
*/
|
||||
export function once<T>(
|
||||
emitter: NodeJS.EventEmitter,
|
||||
@@ -25,3 +37,48 @@ export function once<T>(
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve to false as soon as any of the promises has resolved to a value for which the predicate is
|
||||
* falsey, or resolve to true when all of the promises have resolved to a value for which the predicate is
|
||||
* thruthy, or rejects with the reason of the first promise rejection
|
||||
*
|
||||
* @param promises Promises whose resolved values will be tested by the predicate
|
||||
* @param predicate Predicate to apply
|
||||
* @returns Promise indicating whether the predicate holds for all resolved promise values
|
||||
*/
|
||||
export function every<T>(
|
||||
promises: Array<Promise<T>>,
|
||||
predicate: (value: T) => boolean,
|
||||
): Promise<boolean> {
|
||||
if (promises.length > 0) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let resolvedCount = 0;
|
||||
let done = false;
|
||||
promises.forEach(promise => {
|
||||
promise
|
||||
.then(value => {
|
||||
resolvedCount++;
|
||||
if (!done) {
|
||||
const predicateValue = predicate(value);
|
||||
if (!predicateValue) {
|
||||
resolve(false);
|
||||
done = true;
|
||||
} else if (resolvedCount === promises.length) {
|
||||
resolve(predicateValue);
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
if (!done) {
|
||||
reject(err);
|
||||
done = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve(true);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user