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

Handle multiple events #3

Closed
sindresorhus opened this issue May 8, 2017 · 10 comments
Closed

Handle multiple events #3

sindresorhus opened this issue May 8, 2017 · 10 comments

Comments

@sindresorhus
Copy link
Owner

Sometimes it might be useful to handle multiple events and gather them. The problem is determining when it's done. Either the user would choose how many events to wait for, or they would choose an event that indicates it's done. I'm not entirely sure how to design this. Should it be part of the existing API or a pEvent.multi() method? What should the options be?

If anyone needs this, please add your use-case so I can be better informed on how to design this.

@sindresorhus
Copy link
Owner Author

sindresorhus commented May 8, 2017

Proposal:

// Gathers `data` events until it gets a `finish` event
pEvent.multi(emitter, 'data', {
	doneEvent: 'finish'
}).then(data => {
	console.log(data);
	//=> ['a', 'b']
});

// Gathers 4 `data` events
pEvent.multi(emitter, 'data', {
	count: 4
}).then(data => {
	console.log(data);
	//=> ['a', 'b', 'c', 'd']
});

// Gathers `data` events until it reaches 4 or gets a `finish` event
pEvent.multi(emitter, 'data', {
	count: 4,
	doneEvent: 'finish'
}).then(data => {
	console.log(data);
	//=> ['a', 'b', 'c', 'd']
});

The rejectionEvents option applies here too, but not the multiArgs option.

Could use some opinions on this.


@SamVerschueren @alextes @schnittstabil In case you have time to give an opinion on this. No worries if not.

@schnittstabil
Copy link

I've done some scientific research in the area of complex event processing (CEP) some years ago.
And because of that, I would say handle multiple events and gather them can mean many things. One may want to select/filter, group, join, etc. events (similar to query languages like SQL).

Determining when it's done can become easy with the right tools, e.g. using some non-existent functions/classes:

// e.g. emits every 4 events a 'done' event:
const emitter2 = new CollectEmitter(emitter, {count: 4, doneEvent: 'done'});

pEvent(emitter2, 'done').then(data => {
	//=> ['a', 'b', 'c', 'd']
});

Well, similar can be done with observables – the point I want to make is: doing counting/grouping/etc in the world of emitters/observables would be much more flexible.

@sindresorhus
Copy link
Owner Author

@schnittstabil Thanks for chiming in. Interesting. I hadn't considered that. Although I think that's a bit out of scope of this module, and as you said, better handled by emitters/Observables. I guess I could document that as a tip.

@SamVerschueren
Copy link

Nice idea! I'm just going back and forth on adding it to the current API or using something like pEvent.multi(). The thing is that if you pass in doneEvent or something as count, it implies that you will receive multiple events. But then again, explicit is (almost) always better than implicit. So if I follow that though, pEvent.multi() makes perfect sense.

I agree that the CollectEmitter idea is out of scope. Events are always easier to cover with Observables. So for this library, the proposed idea from @sindresorhus looks good.

@schnittstabil
Copy link

Additionally, functions could be supported as well:

pEvent.multi(fibonacciEmitter, 'data', data => data >= 42).then(data => {
	console.log(data);
	//=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
});

That would allow arbitrary complex done conditions.


A question which comes to my mind: what should be done with the arguments of the doneEvent? E.g. em.emit('finish', 'unicorn')?

@sindresorhus
Copy link
Owner Author

sindresorhus commented May 15, 2017

Additionally, functions could be supported as well:

Good idea. Yeah, that looks flexible enough to solve most problems, while being simple.

A question which comes to my mind: what should be done with the arguments of the doneEvent? E.g. em.emit('finish', 'unicorn')?

I have yet to encounter a done/finish event that emits a value. Maybe we should just see if it actually comes up in real world situations before considering it.

@fregante
Copy link

fregante commented Sep 7, 2017

In short, this is feasible as:

await pEvent(emitter, 'data');
await pEvent(emitter, 'data');
await pEvent(emitter, 'data');
await pEvent(emitter, 'data');

Or

for (let i = 0; i < 4; i++) {
    await pEvent(emitter, 'data');
}

Or

const waitForIt = () => pEvent(emitter, 'data');
waitForIt()
.then(waitForIt)
.then(waitForIt)
.then(waitForIt)

However perhaps promises are not exactly the best way to handle these. Maybe generators?

@sindresorhus
Copy link
Owner Author

@bfred-it Sure, that works too, and it gives more flexibility. The idea with pEvent.multi is to make some common patterns super easy. Like gathering all events or a set amount.

@szmarczak
Copy link
Contributor

My proposal:

pEvent.multi(emitter, event, {
	count: Infinity,
	timeout: Infinity,
	filter: undefined,
	rejectionEvents: ['error'],
	resolveImmediately: true,
	multiArgs: false
});

Examples:

await pEvent.multi(emitter, event, {count: 3});
// => ['a', 'b', 'c']

await pEvent.multi(emitter, event, {rejectionEvents: ['finish']});
// => ['a', 'b', 'c', 'd']

await pEvent.multi(emitter, event, {count: 3, rejectionEvents: ['finish']});
// => ['a', 'b', 'c']

await pEvent.multi(emitter, event, {count: 5, rejectionEvents: ['finish']});
// => ['a', 'b', 'c']

const data = await pEvent.multi(emitter, event, {resolveImmediately: true});
// => []
// 4s later => ['a', 'b', 'c', 'd']

await pEvent.multi(emitter, event, {multiArgs: true, count: 3});
// => [['a', 1], ['b', 2], ['c', 3]]

await pEvent.multi(emitter, event, {count: 3, filter: letter => letter !== 'b'});
// => ['a', 'c', 'd']

@sindresorhus
Copy link
Owner Author

@szmarczak Perfect. I agree with everything.

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

No branches or pull requests

5 participants