You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Promisified equivalent of EventEmitter.once() #20893
Right now we can subscribe to one time events using .once(). Because most (all?) Node event emitters emit an "error" event when an error occurs, it seems reasonable to wrap such events in a Promise. For example:
That way we could leverage async/await flow and error handling:
constmyEmitter=newEventEmitter()functionfoo(){setTimeout(()=>myEmitter.emit('error',newError('foo')),500)}functionbar(){console.log('bar')}(async()=>{try{foo()awaitmyEmitter.oncePromise('ready')bar()// never gets called}catch(err){console.log(err)// "foo"}})()
EventEmitter.prototype.once = function once(type, listener) {
if (typeof listener !== 'function') {
return new Promise((resolve) => this.on(type, _onceWrap(this, type, resolve));
// the old behavior was to fire an error on an invalid arg type - so we
// can count on `once` with a single argument to be free for the taking.
// old behavior:
// const errors = lazyErrors();
// throw new errors.ERR_INVALID_ARG_TYPE('listener', 'Function', listener);
}
this.on(type, _onceWrap(this, type, listener));
return this;
};
@benjamingr That's great, though your implementation does not take care of rejecting the Promise when the error event is fired.
Also I wonder if it's not error prone that '.once' have such different return types depending on the second argument. Might be interesting to consider using a different method name.
That's great, though your implementation does not take care of rejecting the Promise when the error event is fired.
I don't think we should do that since event emitters are very general and also because when there is no error event handler Node.js terminates by default - so adding an event handler for error implicitly would be very surprising behavior in Node.
Also I wonder if it's not error prone that '.once' have such different return types depending on the second argument. Might be interesting to consider using a different method name.
I did but it turns out this is backwards compatible because the current behavior for the second argument is to throw a ERR_INVALID_ARG_TYPE .
A oncePromise would not add additional features to a very basic EventEmitter only syntactic sugar. I feel like there is no huge benefit. Also the correlation between any event and 'error' is just a convention. I think an 'event promisify' library like util.promisify does it with callbacks is where to find such tools, but EventEmitter itself should not have any impl based on conventions (my opinion).
Hey @DaAitch thanks for weighing in, would you mind taking a look at my post here #20909 (comment) and the discussion there with interesting points from several collaborators?
I'm wondering if that would make my motivation for considering this clear.
Also - how do you think we can have a better async/await story?
Activity
benjamingr commentedon May 22, 2018
If we decide it's a good idea I'm willing to go ahead and make a PR, I have a branch with this sitting anyway.
benjamingr commentedon May 22, 2018
It's basically:
kirly-af commentedon May 23, 2018
@benjamingr That's great, though your implementation does not take care of rejecting the Promise when the error event is fired.
Also I wonder if it's not error prone that '.once' have such different return types depending on the second argument. Might be interesting to consider using a different method name.
benjamingr commentedon May 23, 2018
I don't think we should do that since event emitters are very general and also because when there is no
errorevent handler Node.js terminates by default - so adding an event handler forerrorimplicitly would be very surprising behavior in Node.I did but it turns out this is backwards compatible because the current behavior for the second argument is to throw a
ERR_INVALID_ARG_TYPE.events: support `once` with promise
benjamingr commentedon May 23, 2018
I've made a PR @kirly-af to get the discussion going.
DaAitch commentedon May 24, 2018
A
oncePromisewould not add additional features to a very basicEventEmitteronly syntactic sugar. I feel like there is no huge benefit. Also the correlation between any event and 'error' is just a convention. I think an 'event promisify' library likeutil.promisifydoes it with callbacks is where to find such tools, butEventEmitteritself should not have any impl based on conventions (my opinion).benjamingr commentedon May 24, 2018
Hey @DaAitch thanks for weighing in, would you mind taking a look at my post here #20909 (comment) and the discussion there with interesting points from several collaborators?
I'm wondering if that would make my motivation for considering this clear.
Also - how do you think we can have a better
async/awaitstory?simonkcleung commentedon May 25, 2018
This should work:
cjihrig commentedon Mar 5, 2019
I believe this can be closed by #26078.