Events.trigger() is implemented like all event handler as synchronous.
However there are many events
on(name: 'rename', callback: (file: TAbstractFile, oldPath: string) => any, ctx?: any): EventRef
Return type any
allows besides all to use Promise<void>
and have
app.vault.on('rename', renameHandler);
async function renameHandler(file: TAbstractFile, oldPath: string): Promise<void> {
}
The problem with this approach, is that when trigger()
is executed, it returns immediately, not waiting for the async handler to complete its job. And multiple handlers for the same event might end up in the difficult to catch race conditions.
I think, trigger
and tryTrigger
has to be rewritten keeping the possibility of async handlers in mind.
class Events {
private _: Record<string, EventRef[]> = {};
trigger(name: string, ...data: any[]): void {
this.triggerAsync(name, ...data);
}
tryTrigger(evt: EventRef, args: any[]): void {
this.tryTriggerAsync(evt, args);
}
private triggerAsync(name: string, ...data: any[]): Promise<void> {
let eventRefs = this._[name];
if (eventRefs) {
eventRefs = eventRefs.slice();
for (const eventRef of eventRefs) {
await this.tryTriggerAsync(eventRef, data);
}
}
}
private async tryTriggerAsync(evt: EventRef, args: any[]): Promise<void> {
try {
await evt.fn.apply(evt.ctx, args)
} catch (error) {
setTimeout(() => {
throw error;
}, 0);
}
}
}
You could also consider expose those ...Async
methods. I understand that it is not possible to get rid of the sync versions anyways, but I think async versions could also be handy for plugin developers.