react-async-iterators
Version:
The magic of JavaScript async iterators in React ⛓️ 🧬 🔃
50 lines • 2.01 kB
JavaScript
import { promiseWithResolvers } from './promiseWithResolvers.js';
import { callWithArgsOrReturn } from './callWithArgsOrReturn.js';
export { AsyncIterableChannel };
class AsyncIterableChannel {
#isClosed = false;
#nextIteration = promiseWithResolvers();
#currentValue;
constructor(initialValue) {
this.#currentValue = initialValue;
}
put(update) {
if (this.#isClosed) {
return;
}
(async () => {
this.#currentValue = callWithArgsOrReturn(update, this.#currentValue);
await undefined; // Deferring to the next microtick so that an attempt to pull the a value before making multiple rapid synchronous calls to `put()` will make that pull ultimately yield only the last value that was put - instead of the first one as were if this otherwise wasn't deferred.
this.#nextIteration.resolve({ done: false, value: this.#currentValue });
this.#nextIteration = promiseWithResolvers();
})();
}
close() {
this.#isClosed = true;
this.#nextIteration.resolve({ done: true, value: undefined });
}
out = {
value: (() => {
const self = this;
return {
get current() {
return self.#currentValue;
},
};
})(),
[Symbol.asyncIterator]: () => {
const whenIteratorClosed = promiseWithResolvers();
return {
next: () => {
// TODO: Should every iterator of this kind here yield `this.#currentValue` first?...
return Promise.race([this.#nextIteration.promise, whenIteratorClosed.promise]);
},
return: async () => {
whenIteratorClosed.resolve({ done: true, value: undefined });
return { done: true, value: undefined };
},
};
},
};
}
//# sourceMappingURL=AsyncIterableChannel.js.map