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

How does race() resolve things? #22

Open
tabatkins opened this issue Sep 20, 2019 · 1 comment
Open

How does race() resolve things? #22

tabatkins opened this issue Sep 20, 2019 · 1 comment

Comments

@tabatkins
Copy link

race() says that it resolves all the other emitters once the first one resolves.

  1. What does it resolve them to?

  2. How does it resolve Promises?

  3. If we don't want our emitter to be forcibly killed by race(), I suppose we can call em.each() to instead pass a child emitter, right?

@pemrouz
Copy link
Contributor

pemrouz commented Oct 12, 2019

Another great question to discuss. The main use case that has informed this has been the following:

const waitFor = fn => run(race(filter(fn, interval(250)), timeout(10000))
await waitFor(condition)

Notably, since Emitter's are resolvable, in contrast to Promise.race if the condition is fulfilled sooner than the timeout, the timeout will be cleanly cleared, rather than left to prevent your process from exiting and still fire after 10 seconds. Likewise if the timeout fires first, the checking every 250ms will also stop.

  1. I've actually updated it so that it resolves when the first Emitter fires rather than resolves. It's possible to convert any Emitter to one that resolves the first time it fires using the expression until(1, source). However, this just seemed like unnecessary repetition. I'd be keen to hear if you have any thoughts on this. I'm totally happy to be persuaded the former more general semantic was better, and imagine we'll know better for sure when we do wider experimentation and can tighten these screws then.

  2. It resolves to the first value fired. Interestingly, this value does not really seem to be important, probably because you're usually racing against some timeout (it will of course be documented in new docs).

  3. Since Promises are not resolvable or cancellable, it does not do anything with them. Note: There have been a couple of previous attempts to extend Promises to be cancellable. However, that approach generally seems fraught with challenges and I think Emitter is now a better, cleaner primitive for providing this same capability, in particular since it still allows the author to always control the value it resolves too (that's one of the main criticisms of other attempts in the past).

  4. That's 100% correct! That's the easiest way to make a copy connected to the original and provide isolation. emitter.each() would return a new child Emitter that shadows the parent. In keeping with the unidirectionality principle, when resolved, it does not affect the parent. But if the parent was resolved, it would be resolved too (just like Promises). Note: I actually had a copy helper that made this slighter more idiomatic, however it does not seem common to do this. This is largely because most of the time you are, or it's very easy too, vend a new Emitter (e.g. .on('event'), Emitter.from([1,2,3]), etc),

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

No branches or pull requests

2 participants