Playing around with `AsyncIterable`s
| #!/usr/bin/env ts-node | |
| type ValueFn = (index?: number) => any | Promise<any>; | |
| const identity = v => v; | |
| async function* range(start: number, end: number, value: ValueFn = identity) { | |
| let index = start; | |
| while (index < end) { | |
| yield await value(index); | |
| index++; | |
| } | |
| } | |
| type AllIterators<TValue> = | |
| | Iterable<TValue> | |
| | IterableIterator<TValue> | |
| | AsyncIterableIterator<TValue>; | |
| function wait(wait: number): Promise<void> { | |
| return new Promise(resolve => setTimeout(() => resolve(), wait)); | |
| } | |
| function every(ms: number) { | |
| return async function*<TValue>( | |
| generator: AllIterators<TValue> | |
| ): AsyncIterableIterator<TValue> { | |
| for await (let v of generator) { | |
| await wait(ms); | |
| yield v; | |
| } | |
| }; | |
| } | |
| function between(start: number, _end: number): Promise<number> { | |
| const end = _end !== Infinity ? _end : Number.MAX_SAFE_INTEGER; | |
| return new Promise((resolve, reject) => | |
| resolve(Math.floor(start + Math.random() * (end - start + 1))) | |
| ); | |
| } | |
| async function start() { | |
| for await (let value of every(100)( | |
| range(0, Infinity, () => between(1, 10)) | |
| )) { | |
| console.log("value", value); | |
| } | |
| } | |
| start(); |
This comment has been minimized.
This comment has been minimized.
|
As above, you can create an infinite generator, but it can't be reused once it has completed, and unfortunately it appears to move into the completed However, if you wrap a generator with a function like #!/usr/bin/env ts-node
type ValueFn = (index?: number) => any | Promise<any>;
const identity = <TValue>(v: TValue): TValue => v;
async function* range(start: number, end: number, value: ValueFn = identity) {
let index = start;
while (index < end) {
yield await value(index);
index++;
}
}
type AllIterators<TValue> =
| Iterable<TValue>
| IterableIterator<TValue>
| AsyncIterableIterator<TValue>;
const isAsyncIterator = <TValue>(
iterator: any
): iterator is AsyncIterableIterator<TValue> => {
return Symbol.asyncIterator in iterator;
};
const isIterator = <TValue>(
iterator: any
): iterator is IterableIterator<TValue> => {
return Symbol.iterator in iterator;
};
async function* tiptoe<TValue>(iterator: AllIterators<TValue>) {
while (true) {
if (isAsyncIterator(iterator)) {
const { value, done } = await iterator.next();
if (done) {
break;
}
yield value;
} else if (isIterator(iterator)) {
const { value, done } = iterator.next();
if (done) {
break;
}
yield value;
} else if (Array.isArray(iterator)) {
for (let value of iterator) {
yield value;
}
break;
}
}
}
async function start() {
const it = range(1, Infinity);
for await (let v of tiptoe(it)) {
console.log("first run, value", v);
if (v === 50) {
break;
}
}
for await (let v of tiptoe(it)) {
console.log("second run, value", v);
if (v === 100) {
break;
}
}
}
start(); |
This comment has been minimized.
This comment has been minimized.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This comment has been minimized.
sebinsua commentedJul 4, 2019
https://codesandbox.io/s/practical-fermat-5q1ze