Re: oldNode.replaceWith(...collection) edge case

I have two more things to add.

1. One more reason why context node should be allowed as an argument.

These work as intended:

node.before(node)
node.after(node)
node.replaceWith(node)

By passing an additional argument, they suddenly fail:

node.before(node, another)
node.after(node, another)
node.replaceWith(node, another)

This doesn’t feel right.

2. Algorithm performance

The performance hit is based on the assumption that an implementation will follow the spec algorithm closely and use a document fragment when multiple arguments are passed. In reality, I believe an implementation can totally get away from that and insert arguments directly, as long as it can make sure the final DOM structure is correct, mutation records are queued, ranges are modified, etc. Nothing in the algorithm dictates the using of a document fragment.

For example, for the before() method, I can imagine it could be implemented it like this (in pseudo code, ignoring mutation records and range, etc):

ensure context node validity
set prevInserted to null
for node from last argument to first argument, if the argument is a document fragment, from its last child to first child
 if node is the context node
  if prevInserted is not null
   insert node before it
   set prevInserted to node
  else
   set prevInserted to node
   continue
 else
  insert node before the context node
  set prevInserted to node

This algorithm shouldn’t slow normal operations down, and I wonder if the spec could use an algorithm like this and not using document fragment.

> On Jan 21, 2015, at 5:50 PM, Glen Huang <curvedmark@gmail.com> wrote:
> 
> @Boris @Simon
> 
> From the jsperf, looks like Blink is indeed making document fragment obsolete. Run the tests in webkit, although still way faster with document fragment, I believe the gap will narrow in the future. (I really think authors shouldn’t have to rely on it to get good performance).
> 
> Thank you for debunking the myth for me. :)
> 
> Now, let’s go back to the original topic. I brought up document fragment because I wanted to argue that by disallowing passing the context node as an argument, authors would be unable find an equally performant solution. You guys tell me that’s not the case. I agree, and I will drop that.
> 
> But I still don’t feel disallowing that is the right way to go, for two reasons:
> 
> 1. Passing context node as an argument does have a meaningful result, and practical use cases.
> 2. Although the use cases might not come as often, these are native DOM methods, everybody is expected to use them. Given the huge user base, the use cases might not come as rare also.
> 
> I see the argument against it is probably that it may slow down normal operations too. But is that really true? The key here is to find the correct insertion point after the macro action. Although in the spec algorithm, using a transient node seems to be the most performant way (and it slows down normal operations), I doubt it’s impossible for an actual implementation to optimize that.
> 
> This isn't some feature that can be disallowed now and allowed in the future. And by disallowing it, I think it qualifies as a gotcha when you do need it.
> 
> But that’s just my personal feelings. If it turns out it’s really not that cheap to implement. I’d be happy to correctly use before() and after() and not root for something that will slow everybody down. :)
> 
>> On Jan 21, 2015, at 4:52 PM, Simon Pieters <simonp@opera.com> wrote:
>> 
>> On Wed, 21 Jan 2015 00:45:32 +0100, Glen Huang <curvedmark@gmail.com> wrote:
>> 
>>> Ah, thank you for letting me know.
>>> 
>>> I vaguely remember document fragment is introduced just to reduce reflows. Looks like this best practice is obsolete now? (I remember myself wondering why bowsers couldn’t optimize that back then.) Many people still suggest it though, including google (https://developers.google.com/speed/articles/javascript-dom <https://developers.google.com/speed/articles/javascript-dom> the "DocumentFragment DOM Generation” section), and you can find more by googling “why use document fragment".
>> 
>> I think that article is a bit misguided. Changing a class does trigger a reflow, but it doesn't force a reflow while the script is running (maybe it does in old browsers). Asking for layout information does force a reflow.
>> 
>> I think documentfragment has been faster in several browsers and maybe still is, but in Blink at least it appears that the different methods are getting about equally fast. It probably depends on how you do it, though. This jsperf might be interesting:
>> 
>> http://jsperf.com/appendchild-vs-documentfragment-vs-innerhtml/81
>> 
>>> So to recap, when you have the need to pass the context node as an argument along with other nodes, just use before() and after() to insert these other nodes? And even insert them one by one is fine?
>> 
>> Yeah.
>> 
>> -- 
>> Simon Pieters
>> Opera Software
> 

Received on Thursday, 22 January 2015 01:18:50 UTC