-
Notifications
You must be signed in to change notification settings - Fork 2.1k
refactor: extract Queue from IncrementalPublisher and IncrementalGraph #4498
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
|
API simplified, above edited. |
|
How does a Queue differ from a Repeater?
|
|
@yaacovCR Glad to see you're still working on GraphQL. The |
790d53f to
da06fa1
Compare
Queue is a batching async-aware iterator-like protocol meant to be consumed in the following (and only the following) pattern:
> let batch;
> if ((batch = queue.currentBatch()) !== undefined) {
> doSomethingWithBatch(batch);
> }
> while ((batch = await queue.nextBatch) !== undefined) {
> doSomethingWithBatch(batch);
> }
A `push()` methods is provided in the Queue constructor (a la repeaters, see https://repeater.js.org/) so that `push()` can be private to the code that constructs the Queue (although it can be saved to be passed to other code).
A `stop()` method is also provided as a the second argument to the constructor for convienence, but it is also available on the queue object itself so that it can be called by the executor or by the consumer. So this works:
> const queue = new Queue(
> async (push, stop) => {
> push(1);
> push(2)
> await Promise.resolve();
> push(3);
> stop();
> },
> );
>
> const batch1 = Array.from(queue.nextBatch()); // batch1 = [1, 2]
> const batch2 = Array.from(await queue.nextBatchAsync()); // batch2 = [3]
as does this:
> let push;
> const queue = new Queue(
> (_push) => {
> push = _push;
> },
> );
>
> push(1);
> push(2);
>
> const batch1 = Array.from(queue.nextBatch()); // batch1 = [1, 2]
>
> const batch2Promise = queue.nextBatchAsync();
>
> await Promise.resolve();
> push(3);
> queue.stop();
>
> const batch2 = await batch2Promise; // batch2 = [3]
Note: concurrent calls to `currentBatch()` and `nextBatch` will return the same batch and are not encouraged.
A `toAsyncIterable(mapFn)` method transforms coalesces each batch of items into a single value (or undefined if not value is to be emitted for the batch).
Using queues, we are able to remove all logic for handling the implicit queue from IncrementalPublisher, retaining only the `_handleCompletedBatch()`, while adding only the required `push()` and `stop()` calls within the IncrementalGraph.
Tests do not change, except that `.return()` and `.throw()` (but not `next()` have an extra tick secondary to the additional layers of `withCleanup()`, so that the tests required slight adjustment.
for our purposes, we can just halt the executor
1d50c41 to
2f43cea
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
A Queue is a batching async-generator meant to be consumed in the following pattern:
where
mapBatchis a function that takes a batch of typeGenerator<T>and returns a single item of typeU | undefinedwhereundefinedmeans no item is emitted.Items are produced as managed by an executor function passed to the Queue constructor, a la repeaters, see https://repeater.js.org/)
A
push()method is provided as an argument to the executor so thatpush()can be private to the code that constructs the Queue (although it can be saved to be passed to other code).A
stop()method is also provided as a the second argument to the executor for convenience, but it is also available on the queue object itself so that it can be called within the executor or by the consumer to end early. So this works:as does this:
Note: concurrent calls to
subscribewill reference the same queue and are not encouraged.Using queues, we are able to remove all logic for handling the implicit queue from IncrementalPublisher, retaining only the
_handleCompletedBatch(), while adding only the requiredpush()andstop()calls within the IncrementalGraph.Tests do not change, except that we have some extra ticks from the use of our new generators (including the use of
withCleanup()to wrap, and so we have to adjust a few tick-sensitive tests.