-
Notifications
You must be signed in to change notification settings - Fork 208
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
feat(event-emitter): Enable invoking asynchronous handlers #649
Conversation
🦋 Changeset detectedLatest commit: 67f0d9f The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Hi @DavidHavl I know using yarn install --frozen-lockfile |
Hi @yusukebe , ok thank you, |
Hi @DavidHavl ! It's my question, like going back to square one. Is it possible to not pass Context as an argument to c.get('emitter').emit('user:created', user) Because using both |
Thank you for your question @yusukebe. Firstly, as far as I understand, a new context is created for every request. The only way I can think of doing what you are asking is to create new instance of emitter for each request, but that seemed pointless to me as too many objects/instances would be flying around at same time for not a good reason. Initially, I was proposing to send (or not) the context via payload, but I really liked your suggestion few weeks ago to explicitly send the context as extra argument to the Here is a code that shows usage of the emitter (using standalone option) in real application: Please let me know if you have other questions. |
@DavidHavl Thank you for your explanation!
Yeah. I also think passing a context is good. I have an idea, though I don't know whether it's possible or not and whether it's a good design or not. First, define export interface Emitter<EventHandlerPayloads> {
context: Context | undefined
on<Key extends keyof EventHandlerPayloads>(
key: Key,
handler: EventHandler<EventHandlerPayloads[Key]>
): void
off<Key extends keyof EventHandlerPayloads>(
key: Key,
handler?: EventHandler<EventHandlerPayloads[Key]>
): void
emit<Key extends keyof EventHandlerPayloads>(key: Key, payload: EventHandlerPayloads[Key]): void
emit<Key extends keyof EventHandlerPayloads>(
key: Key,
c: Context,
payload: EventHandlerPayloads[Key]
): void
} The definition of emit<Key extends keyof EventHandlerPayloads>(
key: Key,
payloadOrContext: EventHandlerPayloads[Key] | Context,
payload?: EventHandlerPayloads[Key]
) {
// ...
const handlerArray = handlers.get(key as EventKey)
if (handlerArray) {
for (const handler of handlerArray) {
handler(context, realPayload)
}
}
} And set a context in the middleware. Or we can create a setter method instead of accessing the property. export const emitter = <EventHandlerPayloads>(
eventHandlers?: EventHandlers<EventHandlerPayloads>
): MiddlewareHandler => {
// Create new instance to share with any middleware and handlers
const instance = createEmitter<EventHandlerPayloads>(eventHandlers)
return createMiddleware(async (c, next) => {
instance.context = c
c.set('emitter', instance)
await next()
})
} What do you think of this? If you feel it's nonsense, you can ignore it! |
@yusukebe I apologize for late reply. The possible way to achieve the adding Context when initializing emitter is to have the emitter be "request scoped", meaning a new instance of Emitter would be created for each request and destroyed when the request ends. Here are some pros and cons of "request scoped" event emitter that I can think of: Pros:
Cons:
I did also consider options such as "request-scoped event registration only", instance pooling", or "lazy initialization", but none of these would solve the issues sufficiently. Please le me know if you have any questions or suggestions. |
Yeah, you are right. So, let's go with it. One thing. You've changed the API for c.get('emitter').emit(c, 'user:created', user) Is this okay? This middleware was released a few months ago, and there are not so many users, but it will be breaking change. It's up to you, but if you want to follow a semver and don't want to bump a major, I think it's better not to add this change. |
@yusukebe Thank you for the response. |
@yusukebe Any thoughts? |
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.
LGTM!
Hi @DavidHavl Sorry for the late reply! Looks good. I'll merge this and release a new version now. Thank you! |
This update contains the following
Added:
emitAsync
method to the EventEmitter to enable invoking asynchronous handlers.on
method.maxHandlers
that limits number of handlers that can be added to a single event.Changed: