-
Notifications
You must be signed in to change notification settings - Fork 35
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
AsyncEmitter #427
base: master
Are you sure you want to change the base?
AsyncEmitter #427
Conversation
1d27b1e
to
4102ef3
Compare
I added tests that reveal problems and now it’s clear that we need to change data structure for wrappers. Maybe better store them mixed to functions: |
Implemented in a different way. Now we hold AsyncEmitter {
events:
Map {
'eventName' => {
on: Set { listener<Function> },
once: Map { listener<Function> => wrapper<Function> }
},
}
} |
Co-Authored-By: Denys Otrishko <[email protected]> Co-Authored-By: Mykola Bilochub <[email protected]> Co-Authored-By: Dmytro Nechai <[email protected]>
const event = this.events.get(name); | ||
if (!event) return 0; | ||
const { on, once } = event; | ||
return on.size + once.size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can be simplified to:
return event ? event.on.size + event.once.size : 0;
// Get or create event | ||
// name <string> event name | ||
// Returns: { on: <Set>, once: <Set> } } | ||
event(name) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to use Symbol('getListeners')
for this, to make this property "private".
|
||
class AsyncEmitter { | ||
constructor() { | ||
this.events = new Map(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.events = new Map(); | |
this.listeners = new Map(); |
if (!event) return Promise.resolve(); | ||
const { on, once } = event; | ||
const promises = [...on, ...once].map(fn => fn(...args)); | ||
once.clear(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to move this one line up, because some of the listeners may create additional once
listeners.
metatests.test('AsyncEmitter on/emit', async test => { | ||
const ae = new AsyncEmitter(); | ||
|
||
const fn = test.mustCall(async (a, b, c, d) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
const fn = test.mustCall(async (a, b, c, d) => { | |
const fn = test.mustCall(async (...args) => { test.strictSame(args, [1, 2, 3, 4]) }); |
|
||
metatests.test('AsyncEmitter once', async test => { | ||
const ae = new AsyncEmitter(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add a test, to ensure that emit
args are forwarded to once
listener.
once(name, fn) { | ||
if (fn === undefined) { | ||
return new Promise(resolve => { | ||
this.once(name, resolve); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.once(name, resolve); | |
this.once(name, (...args) => resolve(args.length <= 1 ? args[0] : args) | |
); |
}); | ||
|
||
setTimeout(fn, 0); | ||
await ae.once('e1'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto.
I suppose we need to hide counters when waiting for multiple event handlers to this abstraction.