repeater
repeater copied to clipboard
RepeatOrNot
This is an idea for a new feature, either in Repeater or as a separate class in the same project.
The idea: The object returned by new Repeater() should have an additional .then method, which will be a one-time-use variant of .next.
Background: Repeater combinators, Crank JS components etc. can cleverly accept Promises in place of Async Iterables. I would like to write a library that does the reverse of this: provide values that other peoples’ code can use as either a Promise or an Async Iterable.
Example: Say I want to implement a file read() function which can be used in two ways:
const result = await read(name); // Buffered read
and
for await (const chunk of read(name)) { ... } // Streaming read
A good API to help me write this function might be:
function read(filename) {
return new RepeatOrNot(async (push, stop) => {
const emitter = getDataEventEmitter(filename);
const buffer = [];
emitter.on('data', (chunk) => {
if (stop.oneTime) buffer.push(chunk);
else push(chunk);
});
emitter.on('close', () => {
if (stop.oneTime) push(buffer.join(''));
else stop();
}
await stop();
emitter.closeAndCleanUp();
});
}
This could be implemented with the following additional behavior on top of Repeater:
When .then() is called on the returned object:
- we remove [Symbol.asyncIterator], .next, .return etc. from the object. We would do the same to .then if .next were called first.
- the executor is invoked, with an additional property on
stop(nameoneTimeabove) set to true. - When .push() is called by the executor, we resolve the
stoppromise immediately. - If the executor throws or calls stop with an argument before pushing a value, reject the promise.
Sorry for the sluggish response! I hear what you’re saying! I also sometimes wonder about writing simultaneously thenable/async iterable APIs. However, I’m not really sure baking this pattern into the repeater abstraction is the right way to go about things. My guess is, you could probably write your RepeaterOrNot API in user space by composing the repeaters with your own code.
I’m on my phone now, so I’m not really able to write the code that would make this work, but essentially you would create a class which mirrors the Repeater class, construct and retain a repeater instance in the constructor, pass in the modified push and stop functions according to your specification and then implement the then/catch/finally/next/return/throw methods according to your specifications as well?
While I don’t think your proposed API is going to make it in, I encourage to experiment via composition, and if you have any questions or need help, I encourage you to let me know via this issue or by email!