18:55
<Andreu Botella>
Steve Hicks: You previously mentioned that with a single property name on events, developers would have to look up which would be the source of that snapshot for each event. If most events with async sources don't propagate the context but some do, wouldn't developers also have to look up when the context is propagated?
18:55
<Andreu Botella>
and I suspect that would be a lot harder to google
19:55
<Steve Hicks>
Steve Hicks: You previously mentioned that with a single property name on events, developers would have to look up which would be the source of that snapshot for each event. If most events with async sources don't propagate the context but some do, wouldn't developers also have to look up when the context is propagated?
That's a fair point. I really do prefer the consistency, but ultimately I think getting the right default as much as possible is a more important trade-off. I think in order to reason much further about this, we need two things: (1) a more concrete list of events and what context they will run in, and (2) a better understanding of whether the "no context exists" case falls back on the top-level (empty) context or else the registration-time context. What's the best way to collaborate on #1?
19:59
<Andreu Botella>
last time I checked there were 250+ event names in the web platform (which is not the same as distinct events, since e.g. the error event on window is very different from the error event on say WebSocket)
20:00
<Andreu Botella>
only those that have async sources matter here, but I don't think there's a good way to get the full list of those, short of analyzing every single one
20:01
<Andreu Botella>
although maybe there's a way to analyze e.g. chromium code to get a partial list of events that are guaranteed to have async sources
20:01
<Steve Hicks>
I can ask my internal chrome contacts to see if they've got any pointers
20:03
<Andreu Botella>
one thing nicolo-ribaudo pointed out is that we could try to reach out to JS educators, maybe giving some example APIs for libraries that would be using AsyncContext, and let developers tell us which events they'd use those libraries with
20:03
<Andreu Botella>
since we have a selection bias in that first-party developers won't be engaging because they will not be using AsyncContext directly most of the time
20:04
<Steve Hicks>
that's an interesting approach - I'm a little unsure of what it would mean to use an event with a library, though.
20:05
<Steve Hicks>
I imagine a tracing or DI library is generally pretty orthogonal from the event system, so it more comes down to just what events your application uses at all
20:07
<Andreu Botella>
I'm not familiar with DI systems at all, so I'll have to trust you on that
20:07
<littledan>
by DI here, it's referring to the same kind of thing as React Context
20:07
<littledan>
it'll be good for us all to become familiar with these things, as they're a potentially important use of AsyncContext
20:08
<littledan>
an example of a framework that uses this DI terminology is Vue https://vuejs.org/guide/components/provide-inject
20:11
<Steve Hicks>
Well, I think there's a lot more to DI than what react context does (or else I may have a too-limited view of what react context is about, since my primary experience is just to avoid prop drilling). For instance, it's typically used to inject top-level/singleton services, like schedulers, RPC clients, or data stores. My experience with DI is mostly on the server via Guice (in Java) but in that context, it's a pretty different flavor from drilling props. A lot of the motivation tends to be looser coupling to support testing and late-loading.
20:13
<Steve Hicks>
Andreu Botella: you mentioned 250+ event names, but presumably this also doesn't include (e.g.) custom element lifecycle callbacks, mutation/intersection observers, etc.
20:14
<Andreu Botella>
for custom element callbacks, as far as I'm aware they're always either triggered synchronously from JS code, or caused by a user or browser event, so I don't think there are any possible async sources
20:16
<Andreu Botella>
for observers, most of them bunch multiple observations, so calling the callback with only one of them would be a merge
20:17
<Andreu Botella>
in the document I describe exposing the snapshot for each of them in the observation object, if it would be useful
20:18
<Andreu Botella>
Chengzhong Wu pointed out that for PerformanceObserver they would be
20:19
<Chengzhong Wu>
Yeah, resource timing in fetch is only available from PerformanceObserver so it is useful to get each resource timing event's relevant context snapshot
20:33
<Andreu Botella>
another important question: if we use the top-level context for user/browser-sourced events, would users of AsyncContext need a way to tell whether it is the top-level context? or would every possible use only care about its own variables, and it could check whether they have the default values?
20:35
<Andreu Botella>
I'm thinking of userland schedulers, which would have no variables, they would just store a snapshot – is there any use case where it would make sense to do that inside an event listener, and where the scheduler would want to replace the snapshot if it's empty?
20:41
<Steve Hicks>
for custom element callbacks, as far as I'm aware they're always either triggered synchronously from JS code, or caused by a user or browser event, so I don't think there are any possible async sources
One async source I'm aware of is when a contenteditable element is deleted by user interaction.
20:42
<Andreu Botella>
there's never good terminology for this stuff 😮‍💨
20:43
<Andreu Botella>
when I say async source, I'm discouting events caused by user or browser interactions
20:44
<Steve Hicks>
Ah, I thought "user" meant "developer". So you're not counting a UI click initiating a click event as an async source?
20:47
<Andreu Botella>
if we go with not using registration-time always, then we'd have one consistent behavior for events fired synchronously from the action of some JS code, and another consistent behavior (whether top-level context or registration context) for events that were not fired due to the action of some JS code in the same agent
20:48
<Andreu Botella>
what I'm concerned with is cases where you have JS code starting an async operation in the browser that eventually fires an event
20:48
<Andreu Botella>
since the spec and browser changes for those events would have to be handled manually, and it's unfeasible to handle every single one of them in the initial rollout
20:49
<Steve Hicks>
Do you have an example of "JS code starting an async operation in the browser that eventually fires an event"? Are you thinking of e.g. XHR?
20:50
<Andreu Botella>
XHR is a good and common example, which is why I keep using it, but there are many others
20:51
<Andreu Botella>
a lot of those are obscure though
20:53
<Steve Hicks>
I'm not optimistic, but is there any way to hedge here? When we're rolling out userland APIs internally, we try to lock things down as much as possible at the outset so that not-yet-defined behavior is an early error. I'm not coming up with any good way to fail fast if anyone were to try to rely on a specific choice of context in the interim before we figure out what the correct default is.
20:53
<littledan>
Well, I think there's a lot more to DI than what react context does (or else I may have a too-limited view of what react context is about, since my primary experience is just to avoid prop drilling). For instance, it's typically used to inject top-level/singleton services, like schedulers, RPC clients, or data stores. My experience with DI is mostly on the server via Guice (in Java) but in that context, it's a pretty different flavor from drilling props. A lot of the motivation tends to be looser coupling to support testing and late-loading.
I think React Context is used for a lot of things (certainly data stores, not 100% sure about the others)
20:55
<Andreu Botella>
I'm not optimistic, but is there any way to hedge here? When we're rolling out userland APIs internally, we try to lock things down as much as possible at the outset so that not-yet-defined behavior is an early error. I'm not coming up with any good way to fail fast if anyone were to try to rely on a specific choice of context in the interim before we figure out what the correct default is.
Yeah, I can't come up with a way either
20:57
<Steve Hicks>
The sledgehammer approach would just be to make variable.get() throw until a new snapshot is restored, but I don't see that flying.
20:58
<Steve Hicks>
(and even then, people end up depending on errors, etc... web compat is a pain)
20:59
<Justin Ridgewell>
The only future proof default is no context
20:59
<Justin Ridgewell>
Provide both originating and registration via properties
21:02
<Steve Hicks>
I don't think that satisfies the goal that AC-unaware user code does the right thing by defualt. And it doesn't really leave the door open to providing a different context later (e.g. we have a beginTrace API that starts a new trace if there's not one currently active, or opens a child span if there is. But changing an event from no-context to registration context (for example) ends up changing this behavior, which isn't good.
21:46
<Steve Hicks>
Backing up a bit, I wonder how many events are actually ambiguous. I suspect that the majority will be pretty clear. It's a lot of upfront work, but if we can narrow down the list of events that we really don't know what to do with, that might make it easier to talk about. Is something like https://www.w3.org/wiki/List_of_events a good place to start?
21:51
<Andreu Botella>
that looks very outdated, but it might be a place to start
21:52
<Andreu Botella>
the definitive list of events is probably https://github.com/w3c/webref/tree/main/ed/events, scraped directly from web specs
21:52
<Andreu Botella>
although not all of those are specs that are far along in the process to be implementable in browsers, let alone implemented
21:58
<Andreu Botella>
I have a buggy script somewhere that can take webref data and filter it based on MDN's compat data, I can pull it out and try to make it work on events tomorrow if you think it would be useful