-
Notifications
You must be signed in to change notification settings - Fork 296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nerfing all events on all event targets in a serviceworker after initial script evaluation seems odd #371
Comments
I mean, there's the question of why we're doing it at all too, instead of handling this like upload events on XHR. |
It had started by w3c/ServiceWorker#718 (comment) to deterministically detect whether no event handler's registered for a given event (to reduce unnecessary SW start-up delay in such cases.) Over a discussion, we'd setteled on the current behavior. (TL;DR see w3c/ServiceWorker#718 (comment) and below.)
I think this was a miss. This should be only for the events on ServiceWorkerGlobalScope not for all the EventTargets.
Given that it should be only for ServiceWorkerGlobalScope, SW lifecycle events plus all other functional events including fetch, push and future extesions are within the scope of this behavior.
Could you give me a pointer or explain a bit more on this? |
Upload events are based on a flag whose state is determined once fetching starts. I think service workers has that already in place. We check if there are any event listeners registered and store those someplace. |
I don't really see a discussion. I see @jakearchibald asserting that this should be the behavior and no one questioning it, or thinking about how it ties in to other specifications. For example, it introduced inconsistent behavior between
OK, but you're doing this for all events, including random made-up ones the service worker script itself decides to fire. I don't see why this is at all reasonable. |
Basically this: w3c/ServiceWorker#718. The goal was to deterministically detect if a SW opted in to certain functional events. We didn't want to override
This is w3c/ServiceWorker#1004.
Synthetic events do not spin off SW. Note that only SW lifecycle events and functional events run SW. |
@jungkees in theory you can do |
That has precisely 0 discussion about the throwing behavior.
Right, but why? This isn't how the precedent in the platform for this (XHR upload events) works....
Yes, I'm well aware. My discussion about this stuff with @catalinb is what led to this issue being filed. For what it's worth, I expect that the behavior for
during initial script execution and then after initial execution does:
Should that last set throw? Why would it? It doesn't add an event listener, note.
I have no idea what "spin off" means here.
Again, no idea what "run" means here. As @annevk notes, scripts can create and dispatch arbitrary events at a ServiceWorkerGlobalScope. And I mean arbitrary. With arbitrary data on them, for their own use. |
I thought we were only going to do this throwing behavior for fetch event. Why do we need to do it for any other event? Everything else has an API to explicitly opt in to the event. |
That is Run Service Worker the only call sites of which are SW Update/Install/Active, Handle Fetch, Handle Functional Event, and postMessage to SW.
As @annevk noted, SW already does this (but with the has ever been evaluated flag constraint): Run Service Worker step 15.
So this kind of usages is totally feasible
under the uncertainty whether the upload events will be fired. But in the case of SW to meet the original goal of optimizing the behavior (i.e., not starting the SW in the first place), the constraint was needed.
Yes, it throws in the current behavior. It's a matter of whether we'd consider this as a valid constraint for the optimization for SW or not.
I think it was discussed in the f2f lead to this comment: w3c/ServiceWorker#718 (comment). This applies the benefit of not starting the SW that has no event listener for the event regardless of whether the app opted in for the event.
Right. I'm not sure if there's a reasonable way to not throw in the case of CustomEvents. If so, that seems to be an option here. |
OK, so Run Service Worker doesn't fire random events other than some small whitelist? Fine, but so what? ;)
Yes. The event will be fired if there were upload listeners set before send().
I don't see why. Your XHR example would work exactly the same whether XHR had this constraint or not, note...
I don't know what you meant by "current behavior", but it doesn't throw in Gecko, and it doesn't throw per the current spec. Where does it throw? What causes it to throw there?
Well, you could start by only throwing, if you're going to throw at all, for a specific whitelist of event names that are reserved by the SW spec for its own purposes, instead of blanket-throwing on everything in sight. |
You're right. I picked up a wrong example indeed. Proper examples would be cases where the event listers are set up within other event handlers or other asyc callbacks. The point is, considering SW's lifetime, setting up event handlers in async tasks wouldn't guarantee they will be run.
Sorry for the confusion. I meant the behavior that addEventListener throws.
That makes sense. For the exact spec language, I'd want to improve the definition of functional events so it can be used to reference the SW events with future extensions inclusive. |
@jungkees should we really use the precedent of the fetch event for new events? I think it would be better for new things to be opt-in. It also sounds like nobody really knows the rationale for the current setup and nobody implements it, so maybe we should just revisit it and only have the "has ever been evaluated flag" and don't modify |
@annevk, other events are already opt-in. As answered to @wanderview's question, I thought checking the "set of event types to handle" in Handle Functional Event step 4 is generally beneficial by avoiding SW start-up delay for scripts that don't (deterministically) register any listener for the event. I'm not against revisiting the design. Indeed we (SW folks including you and me) had discussed this and settled on the current setup (I admit I missed things when having spec'd them as pointed in this issue) together, so I'd like to hear more comments from the folks before we move on. /cc @slightlyoff, @jakearchibald, @wanderview, @aliams @hober FYI, here's the minute of the f2f where we discussed this issue: https://lists.w3.org/Archives/Public/public-webapps/2016JanMar/0096.html.
|
Note: the problem posed in the OP of w3c/ServiceWorker#718 (comment) is also being addressed by w3c/ServiceWorker#920 effort. We might want to consider that point too. |
There are two intents here:
Eg self.addEventListener('install', () => {
self.addEventListener('activate', () => {
console.log('hello');
});
}); The above is dangerous, as the listener to "activate" will be lost if the service worker closes between dispatching "install" and "activate". I agree that we shouldn't be doing this for all targets as @bzbarsky says. For instance we want devs to be able to create a worker during a fetch event, and this rule prevents adding the For |
The listener you add may depend on the result of information you get asynchronously (e.g. via fetch()), no? |
@bzbarsky if you set a global listener from the result of something async, it'll be lost when the service worker next closes. I can't think of cases where you'd want to add a global listener async. |
Sure, but when it starts up again you'd set it up again, no? I mean, how is this different from setting up a listener directly in the initial script the service worker runs? It's just a difference between a function call and an async function. |
@bzbarsky but the listener would never be invoked, since if it's not added before installation finishes, it won't be a reason to start the service worker. |
I'm talking about the situation where the worker installs a fetch listener and also installs a listener for myFunkyEventIFireMyself, and does the latter async. |
@jakearchibald @jungkees @wanderview did this behavior get implemented? I think I'm okay with what @bzbarsky argues for. That we investigate which listeners were added at the end of some task. We record their event names as being able to start the service worker and we leave everything else as-is. So you can continue to use custom events, including custom events named I think we should probably also only do this for some of the existing event names, such as Thoughts? |
self.addEventListener('push', e => {
self.onfetch = e => {
// A push event will add this fetch listener.
};
}); If we consider the above service worker "has a fetch listener", this would happen:
|
Oh.. right. I had lost the context indeed. It gets us go back to the question 2 and 3 of #371 (comment). |
I've thought about this. I don't think we can avoid throwing here. Functional events themselves are the very starting point of the execution of service workers, and the existence of the event listeners being the criterion for the optimization sounds reasonable to me. I think we should do this for all the functional events. For custom events, they can't start off a service worker in the first place, but we can just let them work as usual within the lifetime of a service worker. We'd still have to change it to allow only |
Why can't we avoid throwing? |
Given that we didn't want to make the fetch opt out, I can't think of any better design choice than relying on the event listeners set during the initial execution. |
Sure, but why does that mean we need to throw if you add another listener later? |
@annevk what's wrong with throwing in this case? The problem with the current spec is it throws if the global is If throwing is bad, we should definitely display a console warning. |
Adding another listener during the initial execution won't throw. The point is we are closing the door at the end of the top-level evaluation to not allow any indeterministic additions. |
Throwing is bad because it breaks the expectations of the event model, as bz argued early on in this thread. It's unclear that we should forbid someone adding a listener for their own synthetic "push" event at any point within the lifetime of the global. |
If that's the sticking point then I'm happy with us switching to a console warning for listeners attached to the global that service worker uses as lifecycle or functional events. When it comes to functional events, we shouldn't spin up the service worker if it isn't in the set of event types to handle. |
Okay, great. @bzbarsky I assume that works for you too? I guess what remains here are tests. But this means that in the DOM, we'll remove these lines:
or alternatively rephrase them with the suggestion to say something in the error console (and also only do it if the context object is the global object). Unfortunately whatwg/console#57 is still open. |
I'm not clear on what exactly is being proposed, so I'm not sure whether it works for me. Is the proposal that we take out all special handling of events on ServiceWorkerGlobalScope apart from possibly having some console warnings? How does that handle the original motivating use cases for this behavior? |
@bzbarsky basically web developers will only spot potential mistakes in the console. The service workers specification will still have special handling in that it observes listeners at a specific point in time. At some point I'll add a "legacy has listener" specification entry point for that, to make it clear that's a thing that exists (and we don't quite like). |
That works for me in terms of the core event processing bits, sure. |
@annevk, stating that in the spec would help. And a few more details about SW behavior:
To make it clear, what do we want to do with the lifecycle events and the message event? I'm not thinking of adding the lifecycle events (install and activate) to this rule as Install and Activate steps change the service worker's state regardless of the existence of the event listeners.
We may want to do this only for functional events I guess as Install and Activate are not checking the set of event types to handle. |
I think it would be okay to check for |
If we want to log something in the console, we should probably only do it if event's type is one of "fetch", "message", ... right? What's the complete list there? (And even that can be a little sketchy, as it might be a legitimate late addition due to synthetic events, but I guess in the majority of cases it'll be a legitimate problem.) |
I think we can use the definition of the functional event. And I can probably add a reference to the complete list of functional events from there. The service worker API page of MDN seems to be a good place we can maintain the list. What do you think?
So, I think the warning message should point out the fact that the late addition for functional events doesn't run the service worker even though it was a legitimate call. |
MDN is not a good normative reference. If you want to maintain a registry, inline it. What about the message event? Is that a functional event? |
Inlining it sounds good to me. I don't think the message event is a functional event. The message event doesn't check the set of event types to handle either. |
This adds the functional events defined by other specifications to the list of events section of the spec. This change is to make the context clearer when specifications refer to the functional event concept. E.g. Fetch needs a reference to it: whatwg/dom#371 (comment).
This changes addEventListener() and removeEventListener() to not throw even after the very first evalution of the service worker script. Instead, this specifies user agents have to show a console warning that the asynchronously added listener's event type will not affect service worker's behavior with the functional event stored during the first evaluation. This change referneces the funcional event concept defined in Service Workers spec, and confines the EventTarge object of the specified behavior to ServiceWorkerGlobalScope object instead of all the platform object in the global object. Related SW issue: w3c/ServiceWorker#1004. Related SW PR: w3c/ServiceWorker#1322. Fixes whatwg#371.
This adds the functional events defined by other specifications to the list of events section of the spec. This change is to make the context clearer when specifications refer to the functional event concept. E.g. Fetch needs a reference to it: whatwg/dom#371 (comment).
This changes addEventListener() and removeEventListener() to not throw even after the very first evalution of the service worker script. Instead, this specifies user agents have to show a console warning that the asynchronously added listener's event type will not affect service worker's behavior with the functional event stored during the first evaluation. This change referneces the funcional event concept defined in Service Workers spec, and confines the EventTarge object of the specified behavior to ServiceWorkerGlobalScope object instead of all the platform object in the global object. Related SW issue: w3c/ServiceWorker#1004. Related SW PR: w3c/ServiceWorker#1322. Fixes whatwg#371.
This changes addEventListener() and removeEventListener() to not throw even after the very first evalution of the service worker script. Instead, this specifies user agents have to show a console warning. Related: w3c/ServiceWorker#1004 and w3c/ServiceWorker#1322. Tests: web-platform-tests/wpt#19496. Fixes #371.
As of today, https://dom.spec.whatwg.org/commit-snapshots/8eb68e48b3f613663425120edc5039d83b3a9de8/#dom-eventtarget-addeventlistener says:
Why are we doing this for all event targets? Why are we even doing it for all events? This makes no sense.
The text was updated successfully, but these errors were encountered: