Re: Mutation events replacement

On Wed, 29 Jun 2011 23:54:47 +0200, Rafael Weinstein <rafaelw@google.com>  
wrote:

> On Wed, Jun 29, 2011 at 7:13 AM, Aryeh Gregor <Simetrical+w3c@gmail.com>  
> wrote:
>> On Tue, Jun 28, 2011 at 5:24 PM, Jonas Sicking <jonas@sicking.cc> wrote:
>>> This new proposal solves both these by making all the modifications
>>> first, then firing all the events. Hence the implementation can
>>> separate implementing the mutating function from the code that sends
>>> out notifications.
>>>
>>> Conceptually, you simply queue all notifications in a queue as you're
>>> making modifications to the DOM, then right before returning from the
>>> function you insert a call like "flushAllPendingNotifications()". This
>>> way you don't have to care at all about what happens when those
>>> notifications fire.
>>
>> So when exactly are these notifications going to be fired?  In
>> particular, I hope non-DOM Core specifications are going to have
>> precise control over when they're fired.  For instance, execCommand()
>> will ideally want to do all its mutations at once and only then fire
>> the notifications (which I'm told is how WebKit currently works).  How
>> will this work spec-wise?  Will we have hooks to say things like
>> "remove a node but don't fire the notifications yet", and then have to
>> add an extra line someplace saying to fire all the notifications?
>> This could be awkward in some cases.  At least personally, I often say
>> things like "call insertNode(foo) on the range" in the middle of a
>> long algorithm, and I don't want magic happening at that point just
>> because DOM Range fires notifications before returning from
>> insertNode.
>>
>> Also, even if specs have precise control, I take it the idea is
>> authors won't, right?  If a library wants to implement some fancy
>> feature and be compatible with users of the library firing these
>> notifications, they'd really want to be able to control when
>> notifications are fired, just like specs want to.  In practice, the
>> only reason this isn't an issue with DOM mutation events is because
>> they can say "don't use them", and in fact people rarely do use them,
>> but that doesn't seem ideal -- it's just saying library authors
>> shouldn't bother to be robust.
>
> In working on Model Driven Views (http://code.google.com/p/mdv), we've
> run into exactly this problem, and have developed an approach we think
> is promising.
>
> The idea is to more or less take Jonas's proposal, but instead of
> firing callbacks immediately before the outer-most mutation returns,
> mutations are recorded for a given observer and handed to it as an
> in-order sequence at the "end" of the event.
>
> var observer = window.createMutationObserver(callback);
> document.body.addSubtreeChangedObserver(observer);
> document.body.addSubtreeAttributeChangedObserver(observer);
> ...
> var div = document.createElement('div');
> document.body.appendChild(div);
> div.setAttribute('data-foo', 'bar');
> div.innerHTML = '<b>something</b> <i>something else</i>';
> div.removeChild(div.childNodes[1]);
> ...
>
> // mutationList is an array, all the entries added to
> // |observer| during the preceding script event
> function callback(mutationList) {
> // mutationList === [
> //  { type: 'ChildlistChanged', target: document.body, inserted: [div] },
> //  { type: 'AttributeChanged', target: div, attrName: 'data-foo' },
> //  { type: 'ChildlistChanged', target: div, inserted: [b, i] },
> //  { type: 'ChildlistChanged', target: div, removed: [i] }
> // ];
> }
>
>>
>> Maybe this is a stupid question, since I'm not familiar at all with
>> the use-cases involved, but why can't we delay firing the
>> notifications until the event loop spins?  If we're already delaying
>> them such that there are no guarantees about what the DOM will look
>> like by the time they fire, it seems like delaying them further
>> shouldn't hurt the use-cases too much more.  And then we don't have to
>> put further effort into saying exactly when they fire for each method.
>
> Agreed.
>
> For context, after considering this issue, we've tentatively concluded
> a few things that don't seem to be widely agreed upon:
>
> 1) In terms of when to notify observers: Sync is too soon. Async (add
> a Task) is too late.
>
> - The same reasoning for why firing sync callbacks in the middle of
> DOM operations is problematic for C++ also applies to application
> script. Calling mutation observers synchronously can invalidate the
> assumptions of the code which is making the modifications. It's better
> to allow one bit of code to finish doing what it needs to and let
> mutation observers operate "later" over the changes.
>
> - Many uses of mutation events would actually *prefer* to not run sync
> because the "originating" code may be making multiple changes which
> more or less comprise a "transaction". For consistency and
> performance, the abstraction which is watching changes would like to
> operate on the final state.
>
> - However, typical uses of mutation events do want to operate more or
> less "in the same event" because they are trying to create a new
> consistent state. They'd like to run after the "application code" is
> finished, but before paint occurs or the next scheduled event runs.

If I understand you correctly, the HTML spec has support for this. It's  
called "await a stable state". For instance, the media resource selection  
algorithm uses it to let the script finish before trying to find a  
<source> to load.

http://www.whatwg.org/specs/web-apps/current-work/complete/webappapis.html#await-a-stable-state
http://www.whatwg.org/specs/web-apps/current-work/complete/the-iframe-element.html#concept-media-load-algorithm


> 2) Because the system must allow multiple "observers" and allow
> observers to make further modifications, it's possible for an
> arbitrary number of mutations to have occurred before any given
> observer is called. Thus is it preferable to simply record what
> happened, and provide the list to the observer.
>
> - An observer can be naive and assume that only "simple" mutations
> have occurred. However, it's more likely that an observer is an
> abstraction (like MDV) which only wants to do work WRT to the net of
> what has happened. This can be done by creating a projection which
> takes the sequence of mutations as input.


-- 
Simon Pieters
Opera Software

Received on Thursday, 30 June 2011 08:44:27 UTC