Add every() and delay() methods back
This commit is contained in:
parent
6ea306536d
commit
db3c0bd63e
52
README.md
52
README.md
@ -1,6 +1,6 @@
|
|||||||
# mysah
|
# mysah
|
||||||
|
|
||||||
Promise, Stream and EventEmitter utils for Node.js
|
**Promise, Stream and EventEmitter utils for Node.js**
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -10,8 +10,10 @@ yarn add mysah
|
|||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
|
|
||||||
|
The following snippet demonstrates most of mysah's current features. More will come!
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const { once, sleep, stream } = require("mysah");
|
const { sleep, once, delay, every, stream } = require("mysah");
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const collector = stream
|
const collector = stream
|
||||||
@ -22,8 +24,16 @@ async function main() {
|
|||||||
.pipe(stream.collect({ objectMode: true }));
|
.pipe(stream.collect({ objectMode: true }));
|
||||||
|
|
||||||
const collected = await once(collector, "data");
|
const collected = await once(collector, "data");
|
||||||
console.log(collected); // [ 'a', 'b', 'c', 'd', 'e' ]
|
await sleep(1000); // undefined (after one second)
|
||||||
await sleep(1000); // Resolve after one second
|
await delay(collected, 1000); // [ 'a', 'b', 'c', 'd', 'e' ] (after another second)
|
||||||
|
await every(
|
||||||
|
[Promise.resolve("ab"), delay("cd", 1000)],
|
||||||
|
c => c.length === 2
|
||||||
|
); // true (after another second)
|
||||||
|
await every(
|
||||||
|
[Promise.resolve("ab"), delay("cd", 1000)],
|
||||||
|
c => c.length === 1
|
||||||
|
); // false (instantly)
|
||||||
}
|
}
|
||||||
main();
|
main();
|
||||||
```
|
```
|
||||||
@ -65,14 +75,40 @@ export declare function concat(
|
|||||||
/**
|
/**
|
||||||
* Resolve after the given delay in milliseconds
|
* Resolve after the given delay in milliseconds
|
||||||
*
|
*
|
||||||
* @param ms - The number of milliseconds to wait
|
* @param ms The number of milliseconds to wait
|
||||||
*/
|
*/
|
||||||
export declare function sleep(ms: number): Promise<{}>;
|
export declare function sleep(ms: number): Promise<{}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a value after the given delay in milliseconds
|
||||||
|
*
|
||||||
|
* @param value Value to resolve
|
||||||
|
* @param ms Number of milliseconds to wait
|
||||||
|
*/
|
||||||
|
export declare function delay<T>(value: T, ms: number): Promise<T>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve once the given event emitter emits the specified event
|
* Resolve once the given event emitter emits the specified event
|
||||||
*
|
*
|
||||||
* @param emitter - The event emitter to watch
|
* @param emitter Event emitter to watch
|
||||||
* @param event - The event to watch
|
* @param event Event to watch
|
||||||
*/
|
*/
|
||||||
export declare function once<T>(emitter: NodeJS.EventEmitter, event: string): Promise<T>;
|
export declare function once<T>(
|
||||||
|
emitter: NodeJS.EventEmitter,
|
||||||
|
event: string,
|
||||||
|
): Promise<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 declare function every<T>(
|
||||||
|
promises: Array<Promise<T>>,
|
||||||
|
predicate: (value: T) => boolean,
|
||||||
|
): Promise<boolean>;
|
||||||
```
|
```
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "mysah",
|
"name": "mysah",
|
||||||
"version": "0.3.4",
|
"version": "0.3.5",
|
||||||
"description": "Promise, Stream and EventEmitter utils for Node.js",
|
"description": "Promise, Stream and EventEmitter utils for Node.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"promise",
|
"promise",
|
||||||
@ -34,7 +34,7 @@
|
|||||||
"@types/node": "^10.12.10",
|
"@types/node": "^10.12.10",
|
||||||
"ava": "^1.0.0-rc.2",
|
"ava": "^1.0.0-rc.2",
|
||||||
"chai": "^4.2.0",
|
"chai": "^4.2.0",
|
||||||
"mysah": "^0.3.3",
|
"mysah": "0.2",
|
||||||
"prettier": "^1.14.3",
|
"prettier": "^1.14.3",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^7.0.1",
|
||||||
"tslint": "^5.11.0",
|
"tslint": "^5.11.0",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import test from "ava";
|
import test from "ava";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
import { once, sleep } from "./utils";
|
import { once, sleep, delay, every } from "./utils";
|
||||||
|
|
||||||
const TimingErrorMarginMs = 50;
|
const TimingErrorMarginMs = 50;
|
||||||
|
|
||||||
@ -14,6 +14,16 @@ test("sleep() resolves after the specified delay in milliseconds", async t => {
|
|||||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
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 => {
|
test("once() resolves only after the specified event is emitted", async t => {
|
||||||
const emitter = new EventEmitter();
|
const emitter = new EventEmitter();
|
||||||
const before = Date.now();
|
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 result = await once(emitter, "done");
|
||||||
const after = Date.now();
|
const after = Date.now();
|
||||||
|
|
||||||
expect(result).to.equal("some-result");
|
expect(result).equal("some-result");
|
||||||
expect(after - before).gte(200);
|
expect(after - before).gte(200);
|
||||||
expect(after - before).closeTo(200, TimingErrorMarginMs);
|
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
|
* 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) {
|
export function sleep(ms: number) {
|
||||||
return new Promise(resolve => {
|
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
|
* Resolve once the given event emitter emits the specified event
|
||||||
*
|
*
|
||||||
* @param emitter - The event emitter to watch
|
* @param emitter Event emitter to watch
|
||||||
* @param event - The event to watch
|
* @param event Event to watch
|
||||||
*/
|
*/
|
||||||
export function once<T>(
|
export function once<T>(
|
||||||
emitter: NodeJS.EventEmitter,
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
22
yarn.lock
22
yarn.lock
@ -1142,6 +1142,18 @@ es6-error@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
|
resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d"
|
||||||
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
|
integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==
|
||||||
|
|
||||||
|
es6-promise@^4.0.3:
|
||||||
|
version "4.2.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.5.tgz#da6d0d5692efb461e082c14817fe2427d8f5d054"
|
||||||
|
integrity sha512-n6wvpdE43VFtJq+lUDYDBFUwV8TZbuGXLV4D6wKafg13ldznKsyEvatubnmUe31zcvelSzOHF+XbaT+Bl9ObDg==
|
||||||
|
|
||||||
|
es6-promisify@^5.0.0:
|
||||||
|
version "5.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||||
|
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
|
||||||
|
dependencies:
|
||||||
|
es6-promise "^4.0.3"
|
||||||
|
|
||||||
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
|
escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.4, escape-string-regexp@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||||
@ -2158,10 +2170,12 @@ multimatch@^2.1.0:
|
|||||||
arrify "^1.0.0"
|
arrify "^1.0.0"
|
||||||
minimatch "^3.0.0"
|
minimatch "^3.0.0"
|
||||||
|
|
||||||
mysah@^0.3.3:
|
mysah@0.2:
|
||||||
version "0.3.3"
|
version "0.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/mysah/-/mysah-0.3.3.tgz#4fd0c0489e9f9f99898d1584b73357f5a60a1dda"
|
resolved "https://registry.yarnpkg.com/mysah/-/mysah-0.2.0.tgz#77bcaaa25829bf874ac40ee5c47069bcf52e7283"
|
||||||
integrity sha512-hiottniB9LFmN6I4SL7VJtz7ahi9w0ndE4PJel7WZ6ovvA1LHRJVmbYTbRsy24rHD762ahwLYadxpDE9j+2K+A==
|
integrity sha1-d7yqolgpv4dKxA7lxHBpvPUucoM=
|
||||||
|
dependencies:
|
||||||
|
es6-promisify "^5.0.0"
|
||||||
|
|
||||||
nan@^2.9.2:
|
nan@^2.9.2:
|
||||||
version "2.11.1"
|
version "2.11.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user