W3C home > Mailing lists > Public > www-dom@w3.org > January to March 2013

Re: Better event listeners

From: Jonas Sicking <jonas@sicking.cc>
Date: Thu, 14 Mar 2013 01:36:50 -0700
Message-ID: <CA+c2ei_F2tfd8bJUokiduk3wHKd36r58ApcO3ENM84TxWfqDcg@mail.gmail.com>
To: Bjoern Hoehrmann <derhoermi@gmx.net>
Cc: Anne van Kesteren <annevk@annevk.nl>, Yehuda Katz <wycats@gmail.com>, www-dom@w3.org, slightlyoff@google.com
On Thu, Mar 14, 2013 at 12:12 AM, Jonas Sicking <jonas@sicking.cc> wrote:
> On Mar 13, 2013 10:04 AM, "Bjoern Hoehrmann" <derhoermi@gmx.net> wrote:
>>
>> * Jonas Sicking wrote:
>> >The exact syntax here is of course to-be-determined, but the idea is
>> >that it's the exact same syntax as the "on" function, except that it
>> >doesn't take a handler-function argument. Instead a Future is returned
>> >and this future is resolved (using the Event object) the first time
>> >the corresponding "on" handler-function would have been called.
>> >
>> >One tricky issue is the exact timing of the call to the .then
>> >function. It would be great if we could enable the resolver function
>> >to do things like call .preventDefault on the event, but that might
>> >require that the .then function is called synchronously which goes
>> >against [1].
>> >
>> >[1] https://github.com/slightlyoff/DOMFuture
>>
>> Could you elaborate on where you see the problem here?
>
> Currently [1] defines that a future is always resolved at the end of
> the current microtask. So when you call resolver.accept it won't
> synchronously call the callbacks registered through .then(). Nor is
> the .state or .value changes synchronously.
>
> Instead these things happen at the end of the microtask.
>
> This works great for most events. For a "click" event fired in
> response to the user clicking a link, we'd call resolver.accept to
> resolve the Future. Since we're not currently in a microtask, that
> means that we would immediately update the Future's state and start
> calling the .then()-registered callbacks.
>
> Another way to look at it is that the implementation of .once() would
> look something like:
>
> EventTarget.prototype.once = function(eventType, options) {
>   var self = this;
>   return new Future(function (resolver) {
>     self.on(eventType, options, function(event)) {
>       resolver.accept(event);
>     });
>   });
> };
>
> Here the returned Future would be resolved at the end of the
> microtask, which means as soon as the event handler exits, but before
> the next event handler runs. I.e. the Future would be resolved at the
> same time as a normal event handler would be run. I.e. things work
> great.
>
> However, if the event is dispatched synchronously, say for example the
> loadstart event dispatched in response to a call to XHR.send(), or a
> custom event dispatched manually using EventTarget.dispatchEvent(),
> things don't work as well.
>
> In this case the entire event dispatch, and calling all event
> handlers, happens as part of a single microtask. So "the end of the
> microtask" isn't reached until after all of the event dispatched has
> happened.
>
> We could solve this by defining that the EventTarget code calls some
> internal hidden function on the resolver which synchronously resolves
> the Future. But that doesn't seem like a good solution.
>
> Ideally I think we'd never fire events synchronously, but rather at
> the end of microtasks or asynchronously, in which case this wouldn't
> be a problem. But that ship sailed many years ago.
>
> I suspect this is something that needs to be fixed in the Futures API
> and not in the event dispatch code.

I filed https://github.com/slightlyoff/DOMFuture/issues/47

/ Jonas
Received on Thursday, 14 March 2013 08:37:48 GMT

This archive was generated by hypermail 2.3.1 : Thursday, 14 March 2013 08:37:50 GMT