infernojs / inferno

:fire: An extremely fast, React-like JavaScript library for building modern user interfaces
https://infernojs.org
MIT License
16.04k stars 636 forks source link

What's the difference from virtual dom libraries? #21

Closed kuraga closed 8 years ago

kuraga commented 8 years ago

Good day!

Say please, what's the difference from virtual dom libraries making Inferno so fast? Say from virtual-dom...

Thanks.

kuraga commented 8 years ago

Ok, now I see readme of perf-spike branch, so another question:

Are there (global) differences unnoted there?

And does Inferno, on dynamic content, diff with real DOM or current DOM structures are converted to virtual DOM and then diffed?

trueadm commented 8 years ago

Hi @kuraga, thanks for checking Inferno out. The key difference is that Inferno uses templates to represent fragments of virtual DOM. The virtual DOM gets pre-compiled once into a DOM static nodes and gets given instructions and a shape. It then uses these to make highly optimal passes to the DOM to create/update/remove the dynamic parts. It never needs to "diff" virtual DOM, it simply diffs the values that get passed into the fragment and mutates the DOM structure it already knows about.

I hope that explanation helped detail what goes on within the core of Inferno!

kuraga commented 8 years ago

@trueadm , thanks very much for reply! But further: Suppose the whole tree is dynamic. There are variables in each attribute, every tag name is a variable and contents of tags are also variables :smile: Which scheme of updating do we have in this case, and are there differences from other libraries here?

trueadm commented 8 years ago

@kuraga in the case that everything is dynamic, it would simply traverse through each shape in the tree and update each one, ensuring the changes are all carried out. This should be a very fast operation, still much faster than typical virtual DOM implementations as they still have to carry out a render to work out what has changed. Inferno already knows what can change so simply does a === check on values and updates as necessary.

kuraga commented 8 years ago

@trueadm ,

does a === check

Left operand is property of Fragment object (e.g. {tag: 'li', attrs: { className: 'row' }, text: text}, and right operand is property of HTMLElement object, am I right?

trueadm commented 8 years ago

@kuraga Sorry I'm a bit lost by that comment. Inferno will build a tree for the fragment {tag: 'li', attrs: { className: 'row' }, text: text}. The tree will consist of shape(s) that are highly optimised objects that do very specific tasks to the DOM or of child shapes in the tree.

In the example given, it would know only to "diff" the text value on that fragment, thus only touching the HTMLElement and its Text child object to change its nodeValue.

kuraga commented 8 years ago

@trueadm, I'm asking about what exactly does it compare with ===.

simply does a === check on values and updates as necessary.

Can you point out a line of code of this check, please?

trueadm commented 8 years ago

@kuraga it's done within the shapes, for example:

const nextValue = getValueWithIndex(nextItem, valueIndex);

if (nextValue !== getValueWithIndex(lastItem, valueIndex)) {
    domNode.firstChild.nodeValue = nextValue;
}
kuraga commented 8 years ago

@trueadm So, shape is compared with shape.

Thanks very much!

Last question: are there plans about unit tests?

trueadm commented 8 years ago

Yes, there are plans for UTs although the ATs provide great coverage and feedback given the fact the API of Inferno is tiny.

On 18 Dec 2015, at 13:07, Alexander Kurakin notifications@github.com wrote:

So, shape is compared with shape.

Thanks very much!

Last question: are there plans about unit tests

— Reply to this email directly or view it on GitHub.

kuraga commented 8 years ago

Thanks very much!

trueadm commented 8 years ago

@kuraga No problem! Inferno has always been about three things:

1 have the absolute best performance in regards to manipulation of the DOM 2 keep a React like API, allowing for people to migrate projects to Inferno with little overhead 3 have the absolute best performance when handing server-side rendered text (Node)

We're still to build on point 3, and point 2 still has some coverage that needs expanding on (stateless components for example). In its current state, Inferno simply destroys every other framework out there in terms of performance (virtual DOM and non virtual DOM frameworks alike). I've managed to get performance almost 30% faster in the vdom benchmark compared to the older Inferno thanks to help from the author of Cito and his methods of template initialisation.

I see great things from Inferno in the future and I'd love to get more people contributing and adding ideas if you're interested.

kuraga commented 8 years ago

@trueadm Big thanks for discussion.

I am just trying to create own minimalistic component-based library. So, immutable model as a dependency, DOM manipulation as a dependency, and Application class (with application loop) and Component class (immutable). See: RotorJS.

It uses virtual-dom. And I like virtual-dom interface but yesterday I opened VDOM Benchmark... And saw that virtual-dom conception isn't most optimized.

As I'm creating RotorJS just-for-fun-and-knowledges I'm interested of other conceptions. The fastest libraries are Inferno, Vidom and Snabbdom. Vidom's creator said that Vidom applies patches directly to DOM instead of "patch vDOM and then re-render the whole DOM using vDOM". As I see, Inferno does the same. Both of you have "some additional optimizations" :smile: but code is too hard to see all of them now.

By the way, which "tricks" have been taken from other libraries? So I'm interested of mechanisms and not real usage. And I'm a fan of conceptions "let's be compatible with standards but not other products", and "good interface and speed instead of simple entry point". So, I :smile: points 1 and 3 but :-1: point 2 :smile: And sure :+1: for 100%-coverage of unit-tests (by the way, it's a good documentation, too!)

I hope I'll understand you're mechanisms, and maybe transfer RotorJS to Inferno. Because I like very much 1) static-parts idea and 2) apply directly to DOM. Hope, there are some more techniques... (which have or would been taken from other libraries, too :smile:) And code will be stable! :smile:

trueadm commented 8 years ago

The author of Cito and I have been working on ideas and concepts for a very long time. I've not taken much inspiration from else-where to be honest as I don't see too much value in what other people are doing in the virtual DOM scene (all attempting to solve the same "problem" even though the problem to begin with shouldn't have been one). I'll keep an eye on RotorJS, it looks promising.

In respect to my point 2, it's simple why I've done this. If Inferno didn't do this, it would add very little value to anyone. The realism is this: if it's not React or React-like, no one will use it. The adoption of React and the fact it's quickly becoming the most used frontend view/component library makes it very hard to beat, especially with Facebook backing it. So in my opinion, it's best to offer an API surface that matches people using React, rather than try and convince them that React's API is all wrong.

stevenvachon commented 8 years ago

@trueadm regarding point 2, couldn't that be handled with another library such as "inferno-react"? React may be nothing in 1.5 years.

trueadm commented 8 years ago

@stevenvachon whilst it's true, React might not be here in 1.5 years, I very much doubt that. React doesn't care about the DOM, it's more the fact it's addressed the hardest problem around, how to properly build componentized UIs regardless of their target endpoint (desktop, mobile, web etc). I don't see any other library coming remotely close to replacing React's principles.

I'm definitely behind a functional approach and using immutable data a single atomic store (i.e. Redux) to work with Inferno – as that's a very smart approach to complicated large scale applications. If people can simply do something like this (this won't work but it will give you an idea): import {Inferno as React} from 'inferno' and their application gains an instant 10-20x performance boost, well that's a very compelling point indeed.

kuraga commented 8 years ago

Yeah, agree with @trueadm ! Further-more I think (every) library should be as more modularized as possible... So, it's good idea to separate JSX (done), Ract-like features and DOM manipulate functions and component functions should (well, may) be in different libs...

trueadm commented 8 years ago

@kuraga I like the idea of separating the DOM from the components, as React does with react-dom. I just haven't seen it as a priority right now.

kuraga commented 8 years ago

Well, you're really fast result and painstaking (as of count of good-stored TODOs in code) approach are more important, you're right! :smile:

leeoniya commented 8 years ago

@trueadm do you plan to have hyperscript [1] or jsonml [2] transpiler (probably augmented with any needed Inferno-isms) so that a dev can use those shortened formats to define templates rather than the long-form required by Inferno's createElement?

i'm also wondering how a template compiled using createElement rather than template strings can determine the immutability of any node without regenerating the template - i did not see any way to indicate node immutability in these cases. does it just fallback to typical vdom recreate-the-world & diff/patch?

[1] https://github.com/dominictarr/hyperscript [2] http://www.jsonml.org/

trueadm commented 8 years ago

Inferno's Inferno.TemplateFactory.createElement is simply a factory method that creates a object literal that looks like { tag: 'div', attrs: {}, children: [ ... ] }. It would be very trivial to write your own that follows any other type of template out there, including hyperscript. These all go inside Inferno templates and works out what is dynamic or not by what is passed through as arguments.

const template = Inferno.createTemplate((val1, val2, val3) => ({tag: 'div', children: [val1, val2, val3]}));
Inferno.render(template('Value 1', 'Value 2', 'Value 3'), document.body);

So super easy to write and customise how you like, either at compile-time (for better performance) or run-time (no need for a transpiler/compiler).

leeoniya commented 8 years ago

ah i see. i think the missing piece in that scenario for me would be something like function argument reflection [1]. that way the template can be compiled once with getters/setters inserted in place of where the arguments are used in the func body so the diff can be done just on the passed args and the setters/DOM patch invoked where they differ.

[1] http://stackoverflow.com/questions/1007981/how-to-get-function-parameter-names-values-dynamically-from-javascript

trueadm commented 8 years ago

@leeoniya if I'm not confusing your question, Inferno does this already. Templates are only compiled once. Each variable in the arguments represents a pointer to where the value exists in the arguments for the fragment.

leeoniya commented 8 years ago

no, no there's no question. just thinking out loud to grok the core idea and clarifying that it uses reflection to determine what parts of the func body are static (during compilation)

trueadm commented 8 years ago

@leeoniya this works the exact same as before. You can't do things like this inside templates val1 + val2 or val1.map(...). Everything is literally based on pointers to values passed into the fragment. Exactly the same as how ES2015 template strings work.

leeoniya commented 8 years ago

got it, thanks!

btw, sorry for disappearing off gitter, i couldn't realistically help with my schedule and spend time troubleshooting the bunch of issues that came up with installing the build dependencies on Windows. Contributing wasn't as simple as "git clone, npm install, write js" :) Maybe i missed something.

trueadm commented 8 years ago

I believe @Kflash fixed that with a new workflow, so you should be able to do that now on Windows! on the perf-spike branch anyway. Which is in far better shape than the new-build branch. Just getting test coverage up to 95%+.

peterwmwong commented 8 years ago

@trueadm Do you have any sense of what the performance of perf-spike is like versus master(or what is on vdom-benchmark)?

trueadm commented 8 years ago

In my testing, the new perk-spike was about 30% faster than the last Inferno on the vdom-benchmark. :)

kuraga commented 8 years ago

@trueadm ,

keep a React like API, allowing for people to migrate projects to Inferno with little overhead

vs

While the cito.vdom API is kept simple

What do you think? Not a good option?

trueadm commented 8 years ago

Maybe we are mistaking different things, I was talking about the Component Lifecycle API. If we're talking about the general API, Inferno's API is vastly simpler than both React and Cito.

Inferno.render() does everything you need, mounting, partial mounting and unmounting. Inferno.renderToString() will do server-side rendering of strings (once complete) and Inferno.createTemplate() will create your templates – that's all there is of the main API.

React's best API is its component API, i.e: componentDidMount, componentWillUpdate etc.

kuraga commented 8 years ago

Hm... Yes. I'm interested about DOM manipulation :smile:

kapouer commented 8 years ago

Can the diff algorithm be used for diffing "real" DOM nodes or is it tied to inferno's vdom implementation ?

trueadm commented 8 years ago

@kapouer Inferno only diffs against Inferno's vdom nodes and tries to avoid touching the DOM where possible (for better performance). The only exception to this is where Inferno needs to hydrate the vdom against the real DOM (which is currently a WIP for 0.8).

kapouer commented 8 years ago

I'm asking because there is no "perfect" solution for diffing real dom nodes using basic level1 api (nodeType, attributes, nodeName, childNodes). Morphdom is not right and diffDOM has subtle errors, hence the interest - but i don't want to take hostages about that :)

renjiza commented 7 years ago

hi there can anyone help me how to use inferno js in php, i mean what must i do for make it working in php, i use inferno v1.0.0 beta 37, thanks before .

LeeYunhang commented 5 years ago

@trueadm Do you have any sense of what the performance of perf-spike is like versus master(or what is on vdom-benchmark)?

This page seems not exists

trueadm commented 5 years ago

@mcooder the benchmark was removed a while ago. This is a very old thread.