Open domfarolino opened 2 weeks ago
FYI I've proposed to expose event.waitUntil
when a listener is asynchronous as there's previous work on that within a Service Worker fetch
listener ... and that didn't go well.
As possible workaround, we ended up polluting the addEventListener
to make it possible to prevent the default (or stop propagation) wen a listener comes from a worker.
Basically if the options contains an invoke
field which is a stopPropagation
or preventDefault
string, or an array with one or more methods to invoke, when the event triggers these methods are invoked.
This works well only if you know AOT you want to prevent that default or stop that (immediate) propagation. It cannot possibly work in any other scenario and it can't work conditionally neither (but that's an implementation detail/limitation).
I wonder if there is an opportunity to integrate the Prioritized Task Scheduling API here. One option would be doing something as simple as passing in a task priority to addEventListener():
I like it!
I think this implies that each unique priority would be dispatched as a distinct (macro)task, and that the scheduler could defer lower priority event listeners as needed, perhaps even after rAF.
Would all event listeners at the same given priority still be coalesced into the same task? Or, if they are async now anyway, should they all be scheduled as if called with scheduler.postTask()
?
FYI I've proposed to expose event.waitUntil when a listener is asynchronous
Interesting! I've made this suggestion before as well, though I wonder if the use case I had in mind was the same as what you suggested?
I think that waitUntil
could be one useful way to express a lazy-loading controller for an event listener. Increasingly frameworks today support lazy-loading controllers/listeners, but rely on synchronous event capture and then later on synthetic event replay, to do so. This is inconvenient and lossy in many ways... though an ideal solution might need to be declarative.
(But, I don't quite see how waitUntil
should help make the initial event dispatch async...)
(But, I don't quite see how waitUntil should help make the initial event dispatch async...)
example code I had in mind:
anything.addEventListener('name', (event) => {
event.waitUntil(new Promise(async (res, rej) => {
const thing = await (await fetch(permision)).text();
if (thing === 'OK') {
event.stopPropagation();
event.preventDefault();
return resolve();
}
reject();
}));
});
This idea won't need any execution priority expectation, it would just flag that event as "unresolved" until whatever asynchronous thing needed to eventually keep going happens.
I hope this makes sense.
Original proposal + discussion: https://github.com/whatwg/html/issues/9540
That makes total sense to me, and overlaps with the "lazy-loaded event listener" use case I mentioned. It's just slightly orthogonal to the original proposal here.
(Not to say that all the async use cases shouldn't be discussed together)
@mmocny to clarify, I am :+1: on this proposal ... literally anything that will start tackling how to deal with async events, as every new API is async these days too, would be a great improvement over the current state. Anything would work to me and, to be honest, I find waitUntil
thing ugly myself, my previous proposal was trying to simply "hack" around the fact there is some documentation and a previous case to consider around its existence ... if we could have a better approach that maybe one day will land in Service Worker too, even better 👋
Here is one short list of use cases for what "async events" might mean to folks, each with potentially different feature requests:
"lazy loading controllers"
"passive event dispatch"
{priority}
seems to me to imply "passive" yet gives even more control."async effects which follow the sync event"
preventDefault
etc from the async., e.g. form validation which needs a network hop first."document unload" use cases
"document loading" use cases
blocking=rendering
for first paint but we don't have a way to block all events on resources like script.I don't know if this is useful extra use case or implementation detail, but:
Perhaps a timeout decides when to dispatch the default action?
I have worked with SerialPort API and discovered the transient activation standard which already works well on Chrome/ium browsers (at least) and it has a transient activation duration spec that might (maybe?) help this proposal forward.
What is the issue with the DOM Standard?
I've heard chatterings in a few different places about interest in asynchronous event listeners on the platform, so I figured I'd file a bug here for some more centralized discussion. The problem: When some action happens on the web platform that results in firing events, all event listeners for that event are immediately, right then & there on the spot, without regard to the priority of the listener relative to surrounding tasks. It's entirely possible that developers wish to know about/respond to some events at a much lower priority than other competing tasks at around the same time. Currently there is no way to signal to the platform, that an event listener should be invoked asynchronously after the platform would ordinarily do so, saving the event listener's invocation for a less-busy/contentious time, in terms of task scheduling and execution.
Enabling this would let developers extend their existing task scheduling / prioritization logic to their event listeners as well. Something very rough along these lines can already be done today:
…but it's pretty limited. First, it still involves immediately invoking user script in response to the event, so we don't actually avoid a big part of that cost. The fact that the queueing / deferral logic is handled immediately in userland is a missed performance opportunity — perhaps a large one? Second, it's not all that ergonomic, and is perhaps harder to schedule the
readClickHandler
relative to other userland tasks that follow a certain scheduling dynamic.I wonder if there is an opportunity to integrate the Prioritized Task Scheduling API here. One option would be doing something as simple as passing in a task priority to
addEventListener()
:Related discussion: https://github.com/WICG/observable/issues/74.
@chrishtr @mmocny @shaseley @mfreed7