[w3c/ServiceWorker] Dynamic Event Handler Registration (#1156)

If my reading is correct, the event handler in the following service worker script will never be invoked:

```js
setTimeout(() => {
    self.addEventListener('install', () => console.log('never invoked'));
  }, 0);
```

On the other hand, both of the handlers created in the following script *will* be invoked:

```js
self.addEventListener('install', () => console.log('always invoked #1'));

setTimeout(() => {
    self.addEventListener('install', () => console.log('always invoked #2'));
  }, 0);
```

The specification has a non-normative note about this behavior:

> Note: If the global object’s associated list of event listeners does not have
> any event listener added at this moment, the service worker’s set of event
> types to handle remains an empty set. The user agents are encouraged to show
> a warning that the event listeners must be added on the very first evaluation
> of the worker script.

But this does not explain the intent. If the goal is to allow the browser to make certain kinds of optimizations when it comes to event dispatch, then it seems like the current behavior is acceptable. But if the goal is to prevent dynamic registration of event handlers, then I believe we'll need additional normative constraints.

The current specification text makes the behavior described above fairly clear, but it also seems like a sub-optimal design. It allows developers to "opt in" to dynamic handler registration through an odd pattern (i.e. initial registration of an empty function). By allowing dynamic registration at all, though, the current language allows developers to define workers whose fundamental behavior is volatile. For instance:

```js
// Register empty handler so I can register additional ones in the future
self.addEventListener('message', () => {});

self.addEventListener('install', () => {
    // non-trivial calculations here...

    self.addEventListener('message', function() {
        // handler written to close around the `install` handler's scope
      });
  });
```

The above worker will behave erratically in cases where the user agent terminates the worker after installation--when the worker is later re-evaluated in the "active" state, it will no longer have the expected `message` event handler.

It may be that the steps necessary to implement this pattern are sufficiently awkward to discourage it, and that it's not worth the effort to protect developers who proceed anyway. At the same time, I'm wondering if any thought has been given to explicitly disallowing the practice. For instance, instead of a warning, cases like these could trigger an exception.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3c/ServiceWorker/issues/1156

Received on Tuesday, 30 May 2017 18:08:41 UTC