Hyperhtml: Needless re-rendering without update dependant on white-space

Created on 31 Mar 2017  ·  13Comments  ·  Source: WebReflection/hyperHTML

I've read the docs with it mentioning that any node with whitespace around it is treated as raw-text and parsed as such, which is perfectly fine, but it also looks like this whitespace controls whether or not a node should be re-rendered, regardless of it there are actually any updates or not.

I've not yet done any performance tests to see what the actual impact is, but in the following example name and each user node in the <ul> is re-rendered, regardless of whether there has been any updates or not.

const update = (render, {name, users = []}) => render`
    <h1>${name}</h1>

    <ul>${users.map(user => hyperHTML.wire(user)`
        <li>${user.login}</li>
    `)}</ul>

    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Harry')}">Harry</button>
    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Sally')}">Sally</button>

    <br />

    <button class="button" onclick="${loadGithubFollowers}">Load Followers</button>
`;

Where as this works as expected:

const update = (render, {name, users = []}) => render`
    <h1>
        ${name}
    </h1>

    <ul>${users.map(user => hyperHTML.wire(user)`
        <li>
            ${user.login}
        </li>
    `)}</ul>

    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Harry')}">Harry</button>
    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Sally')}">Sally</button>

    <br />

    <button class="button" onclick="${loadGithubFollowers('ryardley')}">Load Followers</button>
`;

Surely this causes an unnecessary performance overhead and could potential cause issues when trying to insert DOM nodes or fragments?

I should note that I found this by noticing chrome highlighting DOM changes in devTools. The behaviour seems rather counter intuitive and something I hesitate to suggest using this with our team with having to outline when and where to wrap variables with a space or not, and with no easy way that comes to mind to write a linter that detects when and when it is not appropriate.

help wanted invalid question

All 13 comments

I've not yet done any performance tests ...

...

Surely this causes an unnecessary performance overhead ...

not at all.

Considering one template will update only content and another its content as HTML, so that the two templates do completely different things, whenever you'll have real-world performance issues, compared to any other alternative you can find out there, feel free to file a bug.

The behaviour seems rather counter intuitive and something I hesitate to suggest using this with our team

Here, compare this against Preact or whatever:
http://codepen.io/WebReflection/pen/yMGYEx?editors=0010#0

when and where to wrap variables with a space or not

When you want to change just text content and have sanitized HTML through the native DOM API, that's when you need a space around.

If you need HTML instead of raw text, something I strongly doubt accordingly to your example, use no spaces.

The thing is: do you know when HTML is possible and eventually avoided in terms of XSS and other gotchas through your own logic? Do you want any HTML to pass through?

Good, in that case, no spaces around, you are in charge.

Do you want to show the user name?

Good, there's not a single case on earth you want to enable HTML content, put at least one space around.

We can agree this has nothing to do with hyperHTML 3 basic rules to be in charge, right?

Last, but not least, if you update the list of users for no reason whatsoever, each time you'll have new wires no matter what Chrome shows you in console.

Avoid pointless immutability when you don't need history record of your own changes.

The example I posted was a reduced test case of an example we are using trying to tie together a couple different technologies, but indeed I will find time next week to flush out something a little more complex and see how this may affect real world usage.

Last, but not least, if you update the list of users for no reason whatsoever, each time you'll have new wires no matter what Chrome shows you in console.

Avoid pointless immutability when you don't need history record of your own changes.

We are not at all using immutable objects in this project. Despite what all the hype in the community is right now, I've never encountered the problems that immutable state proposes to solve, and personally I see no need to either feed the garbage collector or inflate memory for no good reason. hyperHTML seems to fit perfectly with this train of thought, so I'm definitely going to be exploring further.

That said, I'm not even talking about updating any variables or properties at all. If I have a simple piece of text in name, and an array of eg. 10000 users, merely running update twice, without altering either variable, or modifying the array in any way, appears to result in the browser iterating every single <li> both times, even though we've not made any alterations.

Here the thing. In native DOM Custom Elements there are two kind of implementations:

  • Chrome wouldn't trigger attributeChangedCallback when the attribute value is exactly the same as it was before
  • WebKit would do that, evene if unexpected, expensie, undesired ...

Now the question:

  • if I explicitly set a property, assuming it's a setter, should I execute that setter even if the value passed along is the same I had before, and without any way to actually know if that was the case?

Well, you set a property. Should the browser consider that as an update? Maybe.

Could the browser be smart enough to avoid unnecessary updates for the same value? Maybe.

Accordingly, hyperHTML is already the fastest alternative to any Virtual DOM you have out there.

In all possible improvements, adding an exponenetial Garbage Collector pressure to check if the previously set value, per each DOM node or attribute, was the same, doesn't seem, or even look, like a smart feature to add.

As it is, the DOM can take care of avoiding unnecessary updates, and this happens already, and the memory retrained by this JS library is kept as small as it can.

If there'll ever be a case when optimizing, at cost of RAM usage, your concerns will result in very faster performance, I'll consider that change.

Today? hyperHTML has almost no rivals in terms of size, simplicity, performance, and memory pressure or consumption so please accept my apologies if I'm a bit skeptical about these kind of premature "bugs".

Thank you.

P.S. ... spaces, is not necessarily new lines 😉

const update = (render, {name, users = []}) => render`
    <h1> ${name} </h1>

    <ul>${users.map(user => hyperHTML.wire(user)`
        <li> ${user.login} </li>
    `)}</ul>

    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Harry')}">Harry</button>
    <button onclick="${emit(ACTIONS.NAME_CHANGED, 'Sally')}">Sally</button>

    <br />

    <button class="button" onclick="${loadGithubFollowers}">Load Followers</button>
`;

FYI, since I do care about improving, I have created and built a version of hyperHTML that retains previous value. The branch is callsed with-previous-value

https://github.com/WebReflection/hyperHTML/tree/with-previous-value

The previous value is retained and set only when it's different in these circumstances:

  • it's an attribute, if identical nothing happens otherwise it sets it
  • it's text content, if identical nothing happens otherwise it sets it
  • it's html, if identical nothing happens otherwise it sets it

Other checks per node were already in place.

From my first and quick benchmarks, I couldn't see any meaningful performance boost but I've seen slightly increased retained memory in benchmarks like the dbmon big table.

Since you claimed possible performance boost, beside performance should never be the reason to chose between no spaces and spaces, since those are for other meaning/purposes, like already explained, I wonder if you'd be so kind to use the two different versions of hyperHTML to actually demonstrate your theory and showing results.

The file and its minified version are already usable.

Let me know how that goes, thank you.

You're explanations definitely make sense and I'm definitely intrigued enough by hyperHTML to be happy to help out where I can.

Indeed my initial concerns where both a mix of unexpected results on how I thought hyperHTML worked, and potentially wrong assumptions on some browser efficiencies, but I'll try and squeeze in some time later this week to put together an example that tests what some of my initial concerns were and see how it fairs, both in terms of expected behaviour and performance across both branches.

Thanks for the awesome work.

Andrea, dumb question coming.... You said above tabs are not necessarily
space. After last f-up I pulled all my \s and you asked I show you
something with a tab.

Are tabs spaces?

What is white space for HTML render?

Prolly obvious. Sorry to pester but a yes tabs white space no not

Depends would be awesome

Thanks and thank you for the work and patience

J
On Mon, Apr 3, 2017 at 5:02 PM Scott-MacD notifications@github.com wrote:

You're explanations definitely make sense and I'm definitely intrigued
enough by hyperHTML to be happy to help out where I can.

Indeed my initial concerns where both a mix of unexpected results on how I
thought hyperHTML worked, and potentially wrong assumptions on some browser
efficiencies, but I'll try and squeeze in some time later this week to put
together an example that tests what some of my initial concerns were and
see how it fairs, both in terms of expected behaviour and performance
across both branches.

Thanks for the awesome work.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/WebReflection/hyperHTML/issues/29#issuecomment-291272962,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AHxnvgkD5r8yhLsdo6iBZMpaIP94UUEJks5rsV5TgaJpZM4Mv8JP
.

>


Jason C. Frazzano Esq.
Founder and Master Coach, Focused Coaching
Stanford University, B.A. M.A., with honors and distinction
Columbia Law School, J.D., Stone Scholar
www.focusedcoaching.com
[email protected]
[email protected]
office: 732-671-1834

What I meant is that anything that is not > and < will be considered something to parse as text.

HTML ignores spaces and tabs and new lines beside < pre > tags so you can use spaces, tabs, new lines as you like without any visual side effect.

It will then be affected by the white-space CSS property. But my guess is that in 99% of cases this property isn't used for anything, besides, as you say, in pre elements where it's white-space: pre

pre content can go as <pre>${content}</pre> because it's already sanitized and most of the time highlighted as HTML.

I've thought about all the cases, don't worry 😁

FYI due to latest updates to the attributes and accessors test logic, there is no more any update to textContent or attributes if the value is the exact same it was before.

This is now consistent with every browser. A bit more RAM needed, but at the end of the day I've double tested it was irrelevant compared to advantages gained cross browser.

Best Regards

Thanks for the update @WebReflection.

Although through testing so far, the real world performance impact has been smaller than I initially expected, it's nice to know that we aren't needlessly updating Dom nodes that haven't changed data.

Best regards and great work.

not just nice, it's necessary when you use special accessors.

As example, if you keep setting <input value="${data.value}"> you won't lose the focus but you'll move the cursor at the end of the input every time input.value = value is performed behind the scene.

Now you can even do the following:

render`
<input
  value="${data.value}"
  oninput="${e => data.value = e.target.value}"
>`

and keep the data updated and call that render any time you want/need

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abaksha-sc picture abaksha-sc  ·  6Comments

dfleury picture dfleury  ·  7Comments

ilyaigpetrov picture ilyaigpetrov  ·  4Comments

moebiusmania picture moebiusmania  ·  6Comments

atirip picture atirip  ·  6Comments