already
Advanced tools
Comparing version 3.2.0 to 3.3.0
@@ -108,4 +108,5 @@ declare const _default: { | ||
export declare function each<T>(eachFn: EachFn<T>): (t: ConcatArray<T | PromiseLike<T>>) => Promise<Array<T>>; | ||
export declare function each<T>(opts: FilterMapOptions, eachFn: EachFn<T>): (t: ConcatArray<T | PromiseLike<T>>) => Promise<Array<T>>; | ||
export declare function each<T>(arr: ConcatArray<T | PromiseLike<T>>, eachFn: EachFn<T>): Promise<Array<T>>; | ||
export declare function eachImpl<T>(eachFn: EachFn<T>): (t: ConcatArray<T | PromiseLike<T>>) => Promise<Array<T>>; | ||
export declare function each<T>(arr: ConcatArray<T | PromiseLike<T>>, opts: FilterMapOptions, eachFn: EachFn<T>): Promise<Array<T>>; | ||
export declare type SomeReturn<R> = Promise<R | false>; | ||
@@ -112,0 +113,0 @@ export declare type SomeSyncReturn<R> = SomeReturn<R> | R | false; |
@@ -229,8 +229,26 @@ export default { | ||
} | ||
export function each(arr, eachFn) { | ||
if (Array.isArray(arr)) | ||
return eachImpl(eachFn)(arr); | ||
return eachImpl(arr); | ||
const defaultEachOptions = { | ||
concurrency: 1 | ||
}; | ||
export function each(arr, opts, eachFn) { | ||
if (Array.isArray(arr)) { | ||
if (typeof opts === "function") { | ||
eachFn = opts; | ||
opts = defaultEachOptions; | ||
} | ||
const _opts = opts; | ||
return eachImpl(_opts, eachFn)(arr); | ||
} | ||
if (typeof arr === "function") { | ||
eachFn = arr; | ||
opts = defaultEachOptions; | ||
} | ||
else { | ||
eachFn = opts; | ||
opts = arr; | ||
} | ||
const _opts = opts; | ||
return eachImpl(_opts, eachFn); | ||
} | ||
export function eachImpl(eachFn) { | ||
function eachImpl(opts, eachFn) { | ||
return async (arr) => { | ||
@@ -242,3 +260,3 @@ const length = arr.length; | ||
} | ||
return map(arr, { concurrency: 1 }, iterator); | ||
return map(arr, opts, iterator); | ||
}; | ||
@@ -245,0 +263,0 @@ } |
@@ -5,3 +5,3 @@ { | ||
"license": "MIT", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"author": "Gustaf Räntilä <g.rantila@gmail.com>", | ||
@@ -8,0 +8,0 @@ "repository": { |
@@ -385,3 +385,3 @@ [![npm version][npm-image]][npm-url] | ||
`each` iterates an array of promises or values, very much like `map`, although always serially as if `concurrency` was set to `1`. | ||
`each` iterates an array of promises or values, very much like `map`, although with a default `concurrency` of `1`. | ||
@@ -407,3 +407,26 @@ The iterator function cannot return a value (or it will be ignored), but can return an empty promise which will be awaited before the next iteration. It's like `tap` but for elements in an array. | ||
### Concurrency and time-chunking | ||
Just like `filter` and `map` have [concurrency](#filter-concurrency) and [time-chunking](#filter-operations-chunked-by-idle-time) options, so does `each`. An optional argument before the predicate/iterator function can be used. | ||
For concurrency: | ||
```ts | ||
import { each } from 'already' | ||
await each( array, { concurrency: 4 }, iteratorFun ); | ||
``` | ||
and for time-chunking: | ||
```ts | ||
import { each } from 'already' | ||
// Time-chunk every 50 milliseconds | ||
await each( array, { chunk: 50 }, iteratorFun ); | ||
// Time-chunk dynamically based on requestIdleCallback() | ||
await each( array, { chunk: 'idle' }, iteratorFun ); | ||
``` | ||
## some | ||
@@ -850,3 +873,3 @@ | ||
Many problems can be generalized to only running one function at a time (awaiting it if necessary). For this, the [`throat`](https://www.npmjs.com/package/throat) package is useful (it is used by `already`). Sometimes a more fine grained control is desired, such as allowing a _test and early return_ as well as signalling that the concurrent logic is complete (to allow the next function call) before the whole function is complete. This results in a more understandable flow. | ||
Many problems can be generalized to only running one function at a time (awaiting it if necessary). For this, [`concurrent`](#concurrent) is useful. Sometimes a more fine grained control is desired, such as allowing a _test and early return_ as well as signalling that the concurrent logic is complete (to allow the next function call) before the whole function is complete. This results in a more understandable flow. | ||
@@ -875,3 +898,3 @@ For this, `funnel()` is extremely handy. | ||
The `getConnection` could be wrapped inside a [`throat`](https://www.npmjs.com/package/throat) wrapper, but that wouldn't be as performant as possible. Consider two calls to `getConnection` when there are connections in the pool, but none is free. One of the two calls should create a new connection, but while this takes place (which may take time), another might be freed. This newly freed connection should be re-usable by the second call to `getConnection`. | ||
The `getConnection` could be wrapped inside a [`concurrent`](#concurrent) wrapper, but that wouldn't be as performant as possible. Consider two calls to `getConnection` when there are connections in the pool, but none is free. One of the two calls should create a new connection, but while this takes place (which may take time), another might be freed. This newly freed connection should be re-usable by the second call to `getConnection`. | ||
@@ -878,0 +901,0 @@ `funnel` makes this trivial. Wrap the `getConnection` logic in a funnel. Allow concurrent access to `getReusableConnection` which is concurrency _safe_. Then create a _synchronization barrier_ (using `shouldRetry`/`retry`): |
73017
890
975