Description
What problem are you trying to solve?
#1038 proposes a method to create a promise that gets resolved once a given event is fired. For example (ignore the name, I don't think it's settled and I just came up with one):
const img = new Image();
img.src = srcURL;
img.addEventListener("load", () => { /* continue doing something with the image */ });
// -->
const img = new Image();
img.src = srcURL;
await img.eventPromise("load");
/* continue doing something with the image */
One problem with that proposal, that is discussed in its comments, is that it does not work with preventDefault
and stopPropagation
, because they need to be called synchronously and thus before that the promise resolves.
What solutions exist today?
/
How would you solve it?
In many cases stopPropagation
/stopImmediatePropagation
/preventDefault
are called unconditionally at the beginning of the event listener callback. For those cases, a declarative API would be enough. Assuming that .waitFor("load")
would take the same options bags as .addEventListener
(only disallowing once
, I guess), then it would look like:
await button.eventPromise("click", { preventDefault: true });
With the .addEventListener
API, it would be:
button.addEventListener("click", e => {
e.preventDefault();
// do stuff
});
// -->
button.addEventListener("click", e => {
// do stuff
}, { preventDefault: true });
I'm opening this as a separate issue from #1038 just because it would also apply to the non-promise API. It's most useful for the promise-based one, but in general it's nice to have declarative alternative to imperative ones.
I'd be curious to know if it'd be helpful for implementations to know that an event is going to be prevented/stopped before calling the callback.
Context
For the web integration of the AsyncContext proposal, we are exploring the possibility of not propagating the context through async JS-caused events.
However, we received feedback that it'd be highly desirable to propagate it for load
/error
event, as their listener is conceptually a continuation of whatever started the loading process.
Events/addEventListener are not the best primitive for signaling completion of some operation, which would be best suited by promises. If we can untangle the "I want to continue do something when this intermediate operation completes" use case (e.g. load
/error
) from the "start this new operation when something happens", we can avoid pushing complexity needed by the first one onto the second.
cc @annevk