const handler = new EventHandler(document.body, 'click')
setTimeout(() => handler.disconnect(), 5000)
for await (const event of handler.getIterator()) {
console.log(event)
}
console.log('end')
Last active
September 28, 2021 11:41
-
-
Save Lcfvs/bc70fbfc309167b1cfecb9ad924dd7b3 to your computer and use it in GitHub Desktop.
An iterable event handler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const registry = new FinalizationRegistry(handler => handler.disconnect()) | |
class EventHandler { | |
#consumed = false | |
#options = null | |
#prevent = false | |
#promises = [] | |
#resolve = null | |
#ref = null | |
#type = null | |
#enqueue = event => { | |
if (this.#resolve) { | |
this.#resolve(event) | |
this.#next() | |
} | |
} | |
#next = () => this.#promises.push(new Promise(this.#wait)) | |
#wait = resolve => this.#resolve = resolve | |
constructor (target, type, { prevent = false, ...options } = {}) { | |
this.#ref = new WeakRef(target) | |
this.#type = type | |
this.#options = options | |
this.#prevent = prevent | |
this.#next() | |
target.addEventListener(type, this, options) | |
registry.register(target, this) | |
} | |
disconnect () { | |
this.#ref.deref()?.removeEventListener(this.#type, this, this.#options) | |
this.#resolve() | |
this.resolve = null | |
} | |
async* getIterator () { | |
if (this.#consumed) { | |
throw new Error('Unable to create an additional iterator') | |
} | |
this.#consumed = true | |
while (this.#resolve || this.#promises.length) { | |
const value = await this.#promises.shift() | |
if (value === undefined) { | |
break | |
} | |
yield value | |
} | |
} | |
async handleEvent (event) { | |
if (this.#prevent) { | |
event.preventDefault() | |
} | |
this.#enqueue(event) | |
} | |
} |
@WebReflection: Yeah, maybe, but we can also some options to automate them, like how I made it for the prevent
:)
@Lcfvs sure thing, all I am saying is that events that are expired are useless. Also having target, coords, etc ... that's not how events work, and the reason in SW you need to explicitly waitUntil
or the event is a dead one, which is not really good.
@WebReflection I see your point but, imho, there is also some cases which doesn't have an event expiration, like:
- to be able to make a cooldown, awaiting some other things but keeping the event order
- to easily make a repeatable step system like this
const step1 = new EventHandler(target1, type, options).getIterator()
const step2 = new EventHandler(target2, type, options).getIterator()
const step3 = new EventHandler(target3, type, options).getIterator()
// ...
for await (const event of step1) {
await step2.next()
await step3.next()
// ...
}
The idea isn't to replace anything, just to have an easy way to do that, solving the same caveats than I presented on the MO proposal.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think asynchronous events aren't a good idea ... as example, you can't
stopPropagation
or evenstopImmediatedPropagation
there, if these actions are done in a tick where the event already bubbled the whole document, right?