Input can be an array, an async iterable or a promise generator. If the promise generator returns
null
when the function is called, the iterator will be considered exhausted.
Alias for skip
, which will discard the first n items from the iterator, c.f.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/drop
Return a new iterator that will discard the first n items from the iterator, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4]).skip(2).collect();
// stream = [2, 3, 4]
Alias for all, which will consume the iterator and return whether the predicate matches all items, c.f. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/every
Consume the iterator and return a boolean if all the items cause the function to return true. It is short circuiting and will return after any item returns false, i.e.
const allEven = await new AsyncArrayStream([2, 4, 6, 8, 10])
.all((item) => item % 2 === 0);
console.log(allEven) // true
or
const allEven = await new AsyncArrayStream([2, 4, 6, 8, 9])
.all((item) => item % 2 === 0);
console.log(allEven) // false
Consume the iterator and return a boolean if any item causes the function to return true. It is short circuiting and will return after any item returns true, i.e.
const hasEven = await new AsyncArrayStream([1, 2, 3, 4, 5])
.any((item) => item % 2 === 0);
console.log(hasEven) // true
or
const hasEven = await new AsyncArrayStream([1, 3, 5])
.any((item) => item % 2 === 0);
console.log(hasEven) // false
Alias for collect, which will consume the iterator and return the items as an array, c.f. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator/toArray
Consume the iterator and return the items in an array. It is identical in functionality to a reduce method with an array that pushes the items, i.e.
const stream = await new AsyncArrayStream([1, 2, 3, 4, 5]).collect();
// stream = [1, 2, 3, 4, 5]
const stream2 = await new AsyncArrayStream([1,2,3,4,5]).reduce((acc, next) => {
acc.push(next);
return acc;
}, []);
// stream2 = [1, 2, 3, 4, 5]
Consume the iterator and return a boolean if all the items cause the function to return true. It is short circuiting and will return after any item returns false, i.e.
const allEven = await new AsyncArrayStream([2, 4, 6, 8, 10])
.all((item) => item % 2 === 0);
console.log(allEven) // true
or
const allEven = await new AsyncArrayStream([2, 4, 6, 8, 9])
.all((item) => item % 2 === 0);
console.log(allEven) // false
Consume the iterator and return a boolean if any item causes the function to return true. It is short circuiting and will return after any item returns true, i.e.
const hasEven = await new AsyncArrayStream([1, 2, 3, 4, 5])
.any((item) => item % 2 === 0);
console.log(hasEven) // true
or
const hasEven = await new AsyncArrayStream([1, 3, 5])
.any((item) => item % 2 === 0);
console.log(hasEven) // false
Return a new iterator that appends the parameter stream to the current stream, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4]).chain([5, 6, 7, 8, 9]).collect();
// stream = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Consume the iterator and return the items in an array. It is identical in functionality to a reduce method with an array that pushes the items, i.e.
const stream = await new AsyncArrayStream([1, 2, 3, 4, 5]).collect();
// stream = [1, 2, 3, 4, 5]
const stream2 = await new AsyncArrayStream([1,2,3,4,5]).reduce((acc, next) => {
acc.push(next);
return acc;
}, []);
// stream2 = [1, 2, 3, 4, 5]
Removes duplicate items from the stream based on a provided callback function. If no callback is provided, a shallow comparison is used, e.g..
const stream = await new AsyncArrayStream([1, 2, 3, 4, 5, 1, 2, 3, 4, 5])
.dedupe()
.collect();
console.log(stream); // [1, 2, 3, 4, 5]
Returns an iterator that will yield a tuple with the index and the item from the iterator, i.e.
const stream = await new AsyncArrayStream([100, 200, 300)
.enumerate()
.collect();
// stream = [[0, 100], [1, 200], [2, 300]]
Add a filter operation to the iterator that will be resolved when the iterator is finalized.
A filter operation should be pure and return a boolean (or Promise
const stream = await new AsyncArrayStream([1, 2, 3, 4, 5])
.filter((item) => item % 2 === 0)
.collect();
console.log(stream); // [2, 4]
Add a filterMap operation to the iterator that will be resolved when the iterator is
finalized. A filterMap operation takes an item of type A and returns
B | null | undefined | false
(or a Promise
that resolves to any of these values).
Any type except B will cause the item to be filtered out. A filterMap functions is
typically pure, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4])
.filterMap((item) => item % 2 === 0 ? item ** 2 : null)
.collect();
// stream = [0, 4, 16]
NOTE: Map functions change the type of the iterator, but if you call the function without reassigning the variable or chaining methods, then the type will be incorrect, i.e.
const stream = new ArrayStream([1, 2, 3, 4, 5])
stream.map(item => String.fromCharCode(item + 65));
then the type of stream will be ArrayStream<number, Breaker<number>>
instead of
ArrayStream<string, Breaker<string>>
. Instead, do one of these two:
const stream = new ArrayStream([1, 2, 3, 4, 5])
.map(item => String.fromCharCode(item + 65));
or
let stream = new ArrayStream([1, 2, 3, 4, 5]);
stream = stream.map(item => String.fromCharCode(item + 65));
Consume the iterator and return the first item that causes the function to return true.
If the item is not found, it will return null
. This method can be used on an infinite
generator but will never return if the item is never found. The function short circuits
on the first item that returns true and will not consume the rest of the iterator, i.e.
const item = await new AsyncArrayStream([1, 2, 3, 4, 5])
.find((item) => item % 2 === 0);
console.log(item); // 2
or
const item = await new AsyncArrayStream([1, 3, 5, 7, 9])
.find((item) => item % 2 === 0);
console.log(item); // null
Consume the iterator and return the index of first item that causes the function to
return true. If the item is not found, it will return -1
. This method can be used
on an infinite generator but will never return if the item is never found.
The function short circuits on the first item that returns true and will not consume
the rest of the iterator, i.e.
const position = await new AsyncArrayStream([1, 2, 3, 4, 5])
.findIndex((item) => item % 2 === 0);
console.log(position); // 1
or
const position = await new AsyncArrayStream([1, 3, 5, 7, 9])
.findIndex((item) => item % 2 === 0);
console.log(position); // -1
Consume the iterator and return the first item that causes the function to
return true starting from the last item in the iteraotr. If the item is not
found, it will return null
. This method cannot be used on an infinite
generator because it needs to consume the entire iterator to start from the end.
The function does not short circuit and will consume the entire iterator, i.e.
const null = await new AsyncArrayStream([1, 2, 3, 4, 5])
.findLast((item) => item % 2 === 0);
console.log(null); // 4
or
const item = await new AsyncArrayStream([1, 3, 5, 7, 9])
.findLast((item) => item % 2 === 0);
console.log(item); // null
Consume the iterator and return the index of the first item that causes the function to
return true starting from the last item in the iteraotr. If the item is not
found, it will return null
. This method cannot be used on an infinite
generator because it needs to consume the entire iterator to start from the end.
The function does not short circuit and will consume the entire iterator, i.e.
const position = await new AsyncArrayStream([1, 2, 3, 4, 5])
.findLastIndex((item) => item % 2 === 0);
console.log(position); // 4
or
const position = await new AsyncArrayStream([1, 3, 5, 7, 9])
.findLastIndex((item) => item % 2 === 0);
console.log(position); // -1
Consume the iterator and collect all items into an array flattened to the specified depth, i.e.
const stream = await new AsyncArrayStream([[1, 2], [3, [4, 5]], [5, [6, [7, 8]]]]).flat(2);
// stream = [1, 2, 3, 4, 5, 5, 6, [7, 8]]
Optional
d: DReturns an iterator where every item is mapped to an array of items, each of which is yielded individually, i.e.
const stream = await new AsyncArrayStream([100, 200, 300)
.flatMap((item) => [item, item + 1]).collect();
// stream = [100, 101, 200, 201, 300, 301]
Add a forEach operation to the iterator that will be resolved when the iterator is finalized.
A forEach operation takes an iterator of type A and returns void or Promise
let sum = 0;
const sum2 = await new AsyncArrayStream([1, 2, 3, 4, 5])
.forEach((item) => sum += item)
.reduce((acc, next) => acc + next, 0);
console.log(sum === sum2); // true
Returns an iterator that will exhaust as soon as the iterator yields a null or undefined value, i.e.
const stream = await new AsyncArrayStream([100, 200, 300, null, 400]).fuse().collect();
// stream = [100, 200, 300]
Consume the iterator and return if any item is equal to the input. This is short circuiting and will return after any item is equal to the input. NOTE: This will not work correctly for reference values, i.e.
const hasTwo = await new AsyncArrayStream([1, 2, 3, 4, 5])
.includes(2);
console.log(hasTwo); // true
but this will not work:
const obj = { a: 1 };
const hasObj = await new AsyncArrayStream([{ a: 1 }, { a: 2 }])
.includes(obj);
console.log(hasObj); // false
Add a forEach operation to the operations, useful for signaling debugging. Defaults to logging the item, i.e.
await new AsyncArrayStream([1, 2, 3, 4, 5])
.inspect()
.collect();
// 1-5 will be logged
Return a new iterator that will include an item between every value returned
by the iterator. The item can be a value or a function that, given the latest
iterated value, returns a value of type Value> (or a Promise
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4]).intersperse(5).collect();
// stream = [0, 5, 1, 5, 2, 5, 3, 5, 4]
or
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4])
.intersperse((item) => item + 100)
.collect();
Add a map operation to the iterator that will be resolved when the iterator is finalized. A map operation takes an item of type A and returns an item of type B (or Promise). A map function is different from forEach in that it should be pure and not have side effects, i.e.
const stream = await new AsyncArrayStream([1, 2, 3, 4, 5])
.map((item) => item * 2)
.collect();
console.log(stream); // [2, 4, 6, 8, 10]
NOTE: Map functions change the type of the iterator, but if you call the function without reassigning the variable or chaining methods, then the type will be incorrect, i.e.
const stream = new ArrayStream([1, 2, 3, 4, 5])
stream.map(item => String.fromCharCode(item + 65));
then the type of stream will be ArrayStream<number, Breaker<number>>
instead of
ArrayStream<string, Breaker<string>>
. Instead, do one of these two:
const stream = new ArrayStream([1, 2, 3, 4, 5])
.map(item => String.fromCharCode(item + 65));
or
let stream = new ArrayStream([1, 2, 3, 4, 5]);
stream = stream.map(item => String.fromCharCode(item + 65));
Consume the iterator and return the item at the nth index (or null if it doesn't exist), i.e.
const stream = await new AsyncArrayStream([100, 200, 300).nth(1);
// stream = 200
Consume the iterator and return a tuple of two arrays, the left being
those that caused the function to return true
, and the right the others, i.e.
const [left, right] = await new AsyncArrayStream([1, 2, 3, 4, 5])
.partition((item) => item % 2 === 0);
console.log(left); // [2, 4]
console.log(right); // [1, 3, 5]
Asynchronously retrieves the next item from the stream without advancing the stream.
If the stream has reached the end, it returns null
, e.g.
const stream = new AsyncArrayStream([1, 2, 3, 4, 5]);
console.log(await stream.peek()); // 1
console.log(await stream.peek()); // 1
const items = await stream.collect();
console.log(items); // [1, 2, 3, 4, 5]
console.log(await stream.peek()); // null
Consume the iterator and collect all items into the chosen data structure starting from the first item, i.e.
const stream = await new AsyncArrayStream([100, 200, 300)
.reduce((acc, next) => acc + next, 0);
console.log(stream) // 600
Consume the iterator and collect all items into the chosen data structure starting from the last item, i.e.
const stream = await new AsyncArrayStream(["a", "b", "c"])
.reduceRight((acc, next) => acc + next, "");
console.log(stream) // "cba"
Return a new iterator that will discard the first n items from the iterator, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4]).skip(2).collect();
// stream = [2, 3, 4]
Return a new iterator that will only include items whose index is divisible by n, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3, 4]).stepBy(2).collect();
// stream = [0, 2, 4]
Return a new iterator that will only include the first n items from the iterator, i.e.
async function* gen() {
let count = 0;
while (true) {
yield count++;
}
}
const stream = await new AsyncArrayStream(gen).take(5).collect();
// stream = [0, 1, 2, 3, 4]
Return a new iterator that will yield the cartesian product of the current iterator and the new one. The new iterator yields a tuple of an item from both data sources. It will be exhausted as soon as either data source is exhausted, i.e.
const stream = await new AsyncArrayStream([0, 1, 2, 3]).zip([5, 6, 7, 8, 9]).collect();
// stream = [[0, 5], [1, 6], [2, 7], [3, 8]]
// NOTE: [4, 9] is not included since the first iterator is exhausted first.
A class that contains an asynchronous iterator and a set of operations to imitate Rust iterators. Operations (map, filter, etc.) are not executed until the iterator is consumed. It can be used with any async or syncronous iterable. It can also work with a function that returns a promise that resolves to an item or null (to signal that the iterator is exhausted).
An example of how this might be used with a fetch request with the promise generator.