Skip to content
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

Unoptimized implementation of pMapIterable preserveOrder option #79

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

tgfisher4
Copy link

Fixes #72.

Spun off from #74 in light of

Summary

Adds a preserveOrder option to pMapIterable, which indicates

Whether the output iterable should produce the results of the mapper on elements of the input iterable in the same order as the elements were produced.
If false, mapper results will be produced in the order they are available, which may not match the order the mapper inputs were produced by the input iterable, but may improve throughput.
Type: boolean
Default: true

Implementation considerations

  • promise must return reference to itself so popRandomPromise can find indexOf.
  • When preserveOrder: false, racing the promises pool is not enough, since trySpawn may be add additional promises to the buffer after the race has begun: so we race an event listener alongside (promises pool is still needed to buffer multiple promises finishing simultaneously.
  • When returnValue === pMapSkip && preserveOrder: false, unlike when preserveOrder: false we have no way to know if returning will cause our promise to win an ongoing race, and so have no way of knowing whether to skip popping ourselves (to allow the main loop to pop us instead). So, when returnValue === pMapSkip, we instead popRandomPromise ourselves unconditionally and instead skip popNextPromise in main while loop.
  • move promise inner try-catch logic to promise.catch (which now also catches when iterator.next() throws)
  • when preserveOrder: false && result.done, some promises in the pool may still be pending, so continue (as a matter of fact, we could probably continue in all cases since the current implementation does not run concurrent iterator.next calls, so if preserveOrder: true && result.done there should be no remaining promises in the queue - but hopefully that will change soon as we think about concurrent iterator.next calls!

…fer and `promiseEmitter`

- move `promise` inner `try-catch` logic to `promise.catch` (now also catches when `iterator.next()` throws)
- when `returnValue === pMapSkip`, `popRandomPromise` unconditionally (skip `popNextPromise` in main `while` loop instead)
- add tests for `preserveOrder: false`, sync throwing mappers/iterables, more intricate `pMapSkip` scenarios
}

trySpawn();

while (promises.length > 0) {
const {error, done, value} = await promises[0]; // eslint-disable-line no-await-in-loop
const {promise, result: {error, done, value}} = await nextPromise(); // eslint-disable-line no-await-in-loop
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inline the function here


promises.push(promise);
promise.then(p => {
Copy link
Contributor

@Richienb Richienb Sep 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use try/catch/async/await here. Also, would be better to use a deferred promise and we call it after anything resolves, instead of racing? https://github.com/sindresorhus/p-defer

// This occurs when `concurrency > 1`: the first `promise` will `trySpawn` and `promises.push` another promise before `await`ing the mapper,
// but the ongoing `Promise.race(promises)` call from `nextPromise` is oblivious to this new promise as it was not present in `promises`
// when the race began.
new Promise(resolve => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is good thinking!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optionally allow pMapIterable to yield results out of order
2 participants