Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimizing Compiler: Tagging ReactElements #3227

Open
sebmarkbage opened this issue Feb 22, 2015 · 6 comments
Open

Optimizing Compiler: Tagging ReactElements #3227

sebmarkbage opened this issue Feb 22, 2015 · 6 comments
Labels

Comments

@sebmarkbage
Copy link
Collaborator

We can make more optimized reconciliation by tagging ReactElements with the "hidden class" of their props.

For example, this is guaranteed to always have three props: className, width, children.

<div className="foo" style={{ width: w, height: 100 }}>{c}</div>

If we could tag every element with these properties with a unique ID:

{ __t: 7, type: 'div', props: { className: 'foo', style: { width: w, height: 5 }, children: c } }

Then we could use the hidden class to generate an optimized diffing algorithm for these instead of iterating over the properties. Presumably, we would only need to do this for type: <string> since we only diff native components.

Bonus points if we can determine which properties are constant. Perhaps using a property descriptor object:

// Constant properties are annotated as 1, other properties are excluded and inferred by props.
var t = { className: 1, style: { height: 1 } };
{ __t: t, type: 'div', props: { className: 'foo', style: { width: w, height: 5 }, children: c } }

We would use a heuristic inside React to determine when to create an optimized differ. For example, after 10+ updates to the same component. Just like a JIT would do.

if (oldElement.__t === newElement.__t) {
  numberOfUpdates++;
} else {
  numberOfUpdates = 0;
}

if (numberOfUpdates === 10) {
  optimizedDiffer = generateOptimizedDiffer(newElement);
  optimizedDiffer(oldElement, newElement);
} else if (numberOfUpdates > 10) {
  optimizedDiffer(oldElement, newElement);
} else {
  manualDiffing(oldElement, newElement);
}
@syranide
Copy link
Contributor

If we could tag every element with these properties with a unique ID:

This seems problematic with watcher builds and generally keeping bundle hashes static for production. Or is this intended to be a production build post-process of some sort? But even then there are problems when separate parts of apps are built/maintained individually.

Then we could use the hidden class to generate an optimized diffing algorithm for these instead of iterating over the properties. Presumably, we would only need to do this for type: since we only diff native components.

This would be very useful for non-DOM elements too I would think (but it would have to be opt-in).

Bonus points if we can determine which properties are constant. Perhaps using a property descriptor object:

It seems to me that you would also want __ts to reference a shared unique ID which would identify the unique set of actual props to check or you'll end up with a potential of O(2^n) differs rather than O(n), n being unique sets of prop names to check.

We would use a heuristic inside React to determine when to create an optimized differ. For example, after 10+ updates to the same component. Just like a JIT would do.

Shouldn't this be globally per __t rather than per instance?

@sophiebits
Copy link
Collaborator

cc @jimfb

@trueadm
Copy link
Contributor

trueadm commented Jan 22, 2016

@sebmarkbage why not instead use the hidden class object to reference props that are dynamic rather than static ones?

var t = { children: 1, style: { width: 1 } };
{ __t: t, type: 'div', props: { className: 'foo', style: { width: w, height: 5 }, children: c } }

Then you'd easily be able to loop through only these props upon doing a patch of the ReactElement.

You could go one step further (would affect backwards compatibility) and make the original ReactElement only return dynamic props plus the hidden class reference. The hidden class would reference all the static props.

Furthermore, you can work out what is static at compile time, depending on how much computation time you want to spend in the compilation stage, for example the following would return as static:

'someString'
1 + 1
foo + 'bar' (given foo is a const)

There are plenty more too, but those are the easy ones to find in the AST.

@sophiebits
Copy link
Collaborator

@trueadm I think @sebmarkbage mentioned that originally with "Bonus points if we can determine which properties are constant.".

@trueadm
Copy link
Contributor

trueadm commented Jan 22, 2016

@spicyj wasn't that referring to the hidden class only referencing props that were constant/static? Sorry, maybe I misunderstood what point of mine you were referencing.

@sophiebits
Copy link
Collaborator

Oh, I totally misread. You're right, my apologies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants