Giter VIP home page Giter VIP logo

Comments (7)

dwighthouse avatar dwighthouse commented on September 25, 2024 1

Thanks @WebReflection ! That was what I was looking for. With the new construction, there's a small initial startup cost (smaller than React), but updates in uhtml are now significantly faster than optimized React.

from uhtml.

WebReflection avatar WebReflection commented on September 25, 2024

I think the misunderstanding is how template literals work here:

const HelperComponent = (item, index) => {
    const computedIndex = index + 1;
    return html.for(item)`${ChildComponent(item, index, computedIndex)}`;
    // it's *you* invoking the function ^^^^ how is any library supposed to avoid that?
};

If you explicitly invoke any function that will be executed. uhtml role is to avoid unnecesary DOM manipulation for nodes that didn't change, and that's it ... how you pass interpolated values to each "hole" it's just your business, and if you invoke a function you just ... well ... invoke a function, right?

With uhtml you define the view, that's it. If you have a state associated uniquely with a view, that's when you use html.for(ref[, id]), but in a template literal, values are retrieved regularly, so that invoking anything, will result into invoking that anything.

Since you come from React, you might consider 3 alternatives:

The latter is based on Custom Elements, so you define their name and you pass them as <my-el> ... others are similar to React, hence maybe easier for you to grasp.

from uhtml.

dwighthouse avatar dwighthouse commented on September 25, 2024

I'm aware why it is happening in my demo. I mentioned as much in the comment:

"Also, because the function for ListItem is called immediately in order to inject it into the template string, it is evaluated immediately, doing unnecessary work for items that have not changed".

The question is: what is the appropriate way to avoid this? Yes, this may not be something implemented by uhtml, but it is a common problem that needs to be understood in the context of using any front end rendering framework.

From what I can see, it comes down to the fact that uhtml accepts as input to a Hole the results of a rendering of html, but not a function that will result in a rendering of html, if called.

I attempted to convert my demo to neverland, but failed. It looks like the version on unpkg and the various versions in your repository don't match. Either way, I don't understand how converting to neverland will actually answer the question I asked. As for uce, I am not interested in browser-based custom elements. I only need to be able to separate different rendering aspects of my app into logical components.

from uhtml.

dwighthouse avatar dwighthouse commented on September 25, 2024

Upon further reflection, I realized that the solution must be in some form of memoization. I will explore that.

from uhtml.

dwighthouse avatar dwighthouse commented on September 25, 2024

Premature optimization strikes again!

On a whim, I used the "fastest memoizer" in JS with my project to memoize the list items in my actual project, not this simplified demo. And I also implemented my actual project in optimized React. And all that compared to plain uhtml, minus a couple of bugs I had introduced earlier (namely, unnecessarily calling html.node).

Adding memoization to uhtml made everything slower by about 100 times. Clearly, I would have to do tremendously expensive operations in every render to make memoization worth it for uhtml renders.

Optimized React + Memoization is about 2 to 3 times faster at making updates than plain uhtml. This isn't saying much, as the difference between them is less than 10 milliseconds. Additionally, React's the startup time is about 5 times slower, though my crude test in React does a lot more during its startup than the bare bones uhtml project I have.

I do still wonder if there is a way to indicate to uhtml when exactly one item in a list changed, and which one, to somehow avoid even the partial operations on the unchanged values. But that's for another time.

from uhtml.

WebReflection avatar WebReflection commented on September 25, 2024

The reason I've mentioned neverland is that it's been created to define components as functions, and it offers useMemo and other React like hooks out of the box.

However, if that's not what you want to do, I suggest using umap and call it a day:

import umap from 'umap';
const memo = umap(new WeakMap);
const HelperComponent = (item, index) => {
    const computedIndex = index + 1;
    return memo.get(item) || memo.set(
      item,
      html.for(item)`${ChildComponent(item, index, computedIndex)}`
    );
};

In above case you ensure you return the computed node related to item once.

Alternatively, your ChildComponent could avoid the expensive operation or cache its result using a similar approach:

const expensiveResults = new WeakMap;
const ListItem = (item, index, onChangeCheckboxAt) => {
    if (!expensiveResults.has(item)) {
    	expensiveResults.set(item, {expensive: 'result'});
    	console.log('Some expensive calculation');
    }

    const onChangeCheckbox = () => {
        onChangeCheckboxAt(!item.checked, index);
    };
    // I still suggest to use `html.for(item)` here, but it's probably not needed
    // unless yoi have Custom Elements in the mix, which doesn't seem to be the case
    return html`
        <li>
            <label>
                <input type="checkbox" onChange=${onChangeCheckbox} .checked=${item.checked} />
                ${item.text}
            </label>
        </li>
    `;
};

The fact an optimized version of React performs better than a library which patterns are different, is not really a surprise to me, but in every benchmark you can find out there, uhtml outperform React by a 5x to 20x+ margin, so maybe it's simply a matter of finding a better pattern for uhtml?

from uhtml.

WebReflection avatar WebReflection commented on September 25, 2024

P.S. with umap, that would be:

const results = umap(new WeakMap);
const ListItem = (item, index, onChangeCheckboxAt) => {
    const result = results.get(item) ||
                   results.set(item, console.log('Some expensive calculation'));

    const onChangeCheckbox = () => {
        onChangeCheckboxAt(!item.checked, index);
    };
    // I still suggest to use `html.for(item)` here, but it's probably not needed
    // unless yoi have Custom Elements in the mix, which doesn't seem to be the case
    return html`
        <li>
            <label>
                <input type="checkbox" onChange=${onChangeCheckbox} .checked=${item.checked} />
                ${item.text}
            </label>
        </li>
    `;
};

from uhtml.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.