Skip to content

Commit 4ea0e9c

Browse files
committed
Add every, some, someStrict utils
1 parent 4474942 commit 4ea0e9c

File tree

10 files changed

+388
-22
lines changed

10 files changed

+388
-22
lines changed

README.md

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,16 @@ A collection of array-related async utilities.
1515

1616
### General utils
1717

18-
#### `asyncMap()`
18+
#### `asyncEvery()`
1919

20-
Creates a new array populated with the results of calling a provided asynchronous function on every element in the calling array.
21-
22-
Note: For optimization purposes, all iterations are ran concurrently. If you rely on any side effects, consider `asyncMapStrict()` instead.
20+
Tests whether all elements in the array pass the test implemented by the provided asynchronous function. It returns a Boolean value.
2321

2422
##### Sample usage
2523

2624
```js
27-
import { asyncMap } from '@wojtekmaj/async-array-utils';
25+
import { asyncEvery } from '@wojtekmaj/async-array-utils';
2826

29-
const asyncMappedArr = await asyncMap([1, 2, 3], async (el, index) => el * 2); // [2, 4, 6]
30-
```
31-
32-
#### `asyncMapStrict()`
33-
34-
Like `asyncMap()`, but runs iterations non-concurrently.
35-
36-
##### Sample usage
37-
38-
```js
39-
import { asyncMapStrict } from '@wojtekmaj/async-array-utils';
40-
41-
const indexes = [];
42-
await asyncMapStrict([1, 2, 3], async (el, index) => { indexes.push(index); return el * 2; }); // [2, 4, 6]
43-
console.log(indexes); // [0, 1, 2]
27+
const largerThanZero = await asyncEvery([1, 2, 3], async (el, index) => el > 0); // true
4428
```
4529

4630
#### `asyncForEach()`
@@ -77,6 +61,34 @@ await asyncForEachStrict(
7761
console.log(indexes); // [0, 1, 2]
7862
```
7963

64+
#### `asyncMap()`
65+
66+
Creates a new array populated with the results of calling a provided asynchronous function on every element in the calling array.
67+
68+
Note: For optimization purposes, all iterations are ran concurrently. If you rely on any side effects, consider `asyncMapStrict()` instead.
69+
70+
##### Sample usage
71+
72+
```js
73+
import { asyncMap } from '@wojtekmaj/async-array-utils';
74+
75+
const asyncMappedArr = await asyncMap([1, 2, 3], async (el, index) => el * 2); // [2, 4, 6]
76+
```
77+
78+
#### `asyncMapStrict()`
79+
80+
Like `asyncMap()`, but runs iterations non-concurrently.
81+
82+
##### Sample usage
83+
84+
```js
85+
import { asyncMapStrict } from '@wojtekmaj/async-array-utils';
86+
87+
const indexes = [];
88+
await asyncMapStrict([1, 2, 3], async (el, index) => { indexes.push(index); return el * 2; }); // [2, 4, 6]
89+
console.log(indexes); // [0, 1, 2]
90+
```
91+
8092
#### `asyncReduce()`
8193

8294
Executes a reducer asynchronous function (that you provide) on each element of the array, resulting in a single output value.
@@ -93,6 +105,32 @@ const result = await asyncReduce(
93105
); // 6
94106
```
95107

108+
#### `asyncSome()`
109+
110+
Tests whether at least one element in the array pass the test implemented by the provided asynchronous function. It returns a Boolean value.
111+
112+
Note: For optimization purposes, all iterations are ran concurrently. If you rely on any side effects or execution order, consider `asyncMapStrict()` instead.
113+
114+
##### Sample usage
115+
116+
```js
117+
import { asyncSome } from '@wojtekmaj/async-array-utils';
118+
119+
const largerThanZero = await asyncSome([1, 2, 3], async (el, index) => el > 0); // true
120+
```
121+
122+
#### `asyncSomeStrict()`
123+
124+
Like `asyncSome()`, but runs iterations non-concurrently.
125+
126+
##### Sample usage
127+
128+
```js
129+
import { asyncSomeStrict } from '@wojtekmaj/async-array-utils';
130+
131+
const largerThanZero = await asyncSomeStrict([1, 2, 3], async (el, index) => el > 0); // true
132+
```
133+
96134
## License
97135

98136
The MIT License.

src/every.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import asyncForEach from './forEach';
2+
3+
export default async function asyncSome(arr, fn) {
4+
return new Promise((resolve) => {
5+
let resolved = false;
6+
// eslint-disable-next-line no-shadow
7+
asyncForEach(arr, async (cur, idx, arr) => {
8+
const result = await fn(cur, idx, arr);
9+
10+
if (!result) {
11+
resolved = true;
12+
resolve(false);
13+
}
14+
}).then(() => {
15+
if (!resolved) {
16+
resolve(true);
17+
}
18+
});
19+
});
20+
}

src/every.spec.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import asyncEvery from './every';
2+
3+
import {
4+
inputArr,
5+
} from '../test-utils';
6+
7+
function largerOrEqualThanZero(x) {
8+
return x >= 0;
9+
}
10+
11+
function largerOrEqualThanZeroInRandomTime(x) {
12+
return new Promise(
13+
(resolve) => setTimeout(() => {
14+
resolve(x >= 0);
15+
}, Math.random() * 100),
16+
);
17+
}
18+
19+
function largerThanOneHundred(x) {
20+
return x > 100;
21+
}
22+
23+
function largerThanOneHundredInRandomTime(x) {
24+
return new Promise(
25+
(resolve) => setTimeout(() => {
26+
resolve(x > 100);
27+
}, Math.random() * 100),
28+
);
29+
}
30+
31+
describe('asyncEvery()', () => {
32+
it.skip('assertions below are valid for synchronous .every()', () => {
33+
const mapper = jest.fn().mockImplementation(largerOrEqualThanZero);
34+
35+
inputArr.every(mapper);
36+
37+
expect.assertions(1 + inputArr.length);
38+
39+
expect(mapper).toHaveBeenCalledTimes(inputArr.length);
40+
inputArr.forEach((el, idx) => {
41+
expect(mapper).toHaveBeenCalledWith(el, idx, inputArr);
42+
});
43+
});
44+
45+
it('iterates over values properly', async () => {
46+
const mapper = jest.fn().mockImplementation(largerOrEqualThanZeroInRandomTime);
47+
48+
await asyncEvery(inputArr, mapper);
49+
50+
expect.assertions(1 + inputArr.length);
51+
52+
expect(mapper).toHaveBeenCalledTimes(inputArr.length);
53+
inputArr.forEach((el, idx) => {
54+
expect(mapper).toHaveBeenCalledWith(el, idx, inputArr);
55+
});
56+
});
57+
58+
it.skip('assertions below are valid for synchronous .every()', () => {
59+
const mapper = jest.fn().mockImplementation(largerOrEqualThanZero);
60+
61+
const result = inputArr.every(mapper);
62+
63+
expect(result).toEqual(true);
64+
});
65+
66+
it('returns truthy result properly', async () => {
67+
const mapper = jest.fn().mockImplementation(largerOrEqualThanZeroInRandomTime);
68+
69+
const result = await asyncEvery(inputArr, mapper);
70+
71+
expect(result).toEqual(true);
72+
});
73+
74+
it.skip('assertions below are valid for synchronous .every()', () => {
75+
const mapper = jest.fn().mockImplementation(largerThanOneHundred);
76+
77+
const result = inputArr.every(mapper);
78+
79+
expect(result).toEqual(false);
80+
});
81+
82+
it('returns falsy result properly', async () => {
83+
const mapper = jest.fn().mockImplementation(largerThanOneHundredInRandomTime);
84+
85+
const result = await asyncEvery(inputArr, mapper);
86+
87+
expect(result).toEqual(false);
88+
});
89+
});

src/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import asyncForEach from './forEach';
22
import asyncForEachStrict from './forEach_strict';
3+
import asyncEvery from './every';
34
import asyncMap from './map';
45
import asyncMapStrict from './map_strict';
56
import asyncReduce from './reduce';
7+
import asyncSome from './some';
8+
import asyncSomeStrict from './some_strict';
69

710
export {
811
asyncForEach,
912
asyncForEachStrict,
13+
asyncEvery,
1014
asyncMap,
1115
asyncMapStrict,
1216
asyncReduce,
17+
asyncSome,
18+
asyncSomeStrict,
1319
};

src/index.spec.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import {
22
asyncForEach,
33
asyncForEachStrict,
4+
asyncEvery,
45
asyncMap,
56
asyncMapStrict,
67
asyncReduce,
8+
asyncSome,
9+
asyncSomeStrict,
710
} from './index';
811

912
describe('index', () => {
@@ -15,6 +18,10 @@ describe('index', () => {
1518
expect(asyncForEachStrict).toBeInstanceOf(Function);
1619
});
1720

21+
it('has asyncEvery exported properly', () => {
22+
expect(asyncEvery).toBeInstanceOf(Function);
23+
});
24+
1825
it('has asyncMap exported properly', () => {
1926
expect(asyncMap).toBeInstanceOf(Function);
2027
});
@@ -26,4 +33,12 @@ describe('index', () => {
2633
it('has asyncReduce exported properly', () => {
2734
expect(asyncReduce).toBeInstanceOf(Function);
2835
});
36+
37+
it('has asyncSome exported properly', () => {
38+
expect(asyncSome).toBeInstanceOf(Function);
39+
});
40+
41+
it('has asyncSomeStrict exported properly', () => {
42+
expect(asyncSomeStrict).toBeInstanceOf(Function);
43+
});
2944
});

src/some.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import asyncForEach from './forEach';
2+
3+
export default async function asyncSome(arr, fn) {
4+
return new Promise((resolve) => {
5+
let resolved = false;
6+
// eslint-disable-next-line no-shadow
7+
asyncForEach(arr, async (cur, idx, arr) => {
8+
const result = await fn(cur, idx, arr);
9+
10+
if (result) {
11+
resolved = true;
12+
resolve(true);
13+
}
14+
}).then(() => {
15+
if (!resolved) {
16+
resolve(false);
17+
}
18+
});
19+
});
20+
}

src/some.spec.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import asyncSome from './some';
2+
3+
import {
4+
inputArr,
5+
largerThanTwo,
6+
largerThanTwoInRandomTime,
7+
largerThanOneHundred,
8+
largerThanOneHundredInRandomTime,
9+
} from '../test-utils';
10+
11+
const firstElementLargerThanTwo = inputArr.findIndex(largerThanTwo);
12+
13+
describe('asyncSome()', () => {
14+
it.skip('assertions below are valid for synchronous .some()', () => {
15+
const mapper = jest.fn().mockImplementation(largerThanTwo);
16+
17+
inputArr.some(mapper);
18+
19+
expect.assertions(firstElementLargerThanTwo);
20+
21+
inputArr.slice(0, firstElementLargerThanTwo).forEach((el, idx) => {
22+
expect(mapper).toHaveBeenCalledWith(el, idx, inputArr);
23+
});
24+
});
25+
26+
it('iterates over values properly', async () => {
27+
const mapper = jest.fn().mockImplementation(largerThanTwoInRandomTime);
28+
29+
await asyncSome(inputArr, mapper);
30+
31+
expect.assertions(firstElementLargerThanTwo);
32+
33+
inputArr.slice(0, firstElementLargerThanTwo).forEach((el, idx) => {
34+
expect(mapper).toHaveBeenCalledWith(el, idx, inputArr);
35+
});
36+
});
37+
38+
it.skip('assertions below are valid for synchronous .some()', () => {
39+
const mapper = jest.fn().mockImplementation(largerThanTwo);
40+
41+
const result = inputArr.some(mapper);
42+
43+
expect(result).toEqual(true);
44+
});
45+
46+
it('returns truthy result properly', async () => {
47+
const mapper = jest.fn().mockImplementation(largerThanTwoInRandomTime);
48+
49+
const result = await asyncSome(inputArr, mapper);
50+
51+
expect(result).toEqual(true);
52+
});
53+
54+
it.skip('assertions below are valid for synchronous .some()', () => {
55+
const mapper = jest.fn().mockImplementation(largerThanOneHundred);
56+
57+
const result = inputArr.some(mapper);
58+
59+
expect(result).toEqual(false);
60+
});
61+
62+
it('returns falsy result properly', async () => {
63+
const mapper = jest.fn().mockImplementation(largerThanOneHundredInRandomTime);
64+
65+
const result = await asyncSome(inputArr, mapper);
66+
67+
expect(result).toEqual(false);
68+
});
69+
});

src/some_strict.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export default async function asyncSomeStrict(arr, fn) {
2+
for (let idx = 0; idx < arr.length; idx += 1) {
3+
const cur = arr[idx];
4+
5+
// eslint-disable-next-line no-await-in-loop
6+
const result = await fn(cur, idx, arr);
7+
8+
if (result) {
9+
return true;
10+
}
11+
}
12+
13+
return false;
14+
}

0 commit comments

Comments
 (0)