State to Screen
About Me
- github.com/Swatinem
- Front End Engineer at Pagestrip
- regular speaker at ViennaJS, not so much lately
- long JS experience
- very performance conscious
- ranting a lot about faults in the JS ecosystem
please don’t take things personally, I love you all :-)
how come modern games look like this, and run smoothly at 60 fps
60 fps
90 fps
because VR
conservatively, that’s a ~10ms budget per frame
where is js at?
Simplified App architecture
State (Domain Models) --> View (DOM / CSS) --> Screen
User (Actions) --> Update State
Lets start at the end
A brief history of 3D APIs
// OpenGL 1 fixed function pipeline, circa 1992
glColor3f(0.0f, 0.0f, 0.0f);
glBegin(GL_TRIANGLES);
glVertex3f( 0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f,-1.0f, 0.0f);
glVertex3f( 1.0f,-1.0f, 0.0f);
glEnd();
// kind of reminds me of
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "#000";
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(100, 100);
ctx.stroke();
// this is called *immediate mode* graphics
// which means you basically throw away everything
// and redraw the whole frame
Drawing in Browsers
- APIs improved, but 2d graphics still mostly immediate mode.
- Browsers try to "cheat" a lot => Layers
- Render into texture, composite texture
- can lead to artifacts => blurry text
(mostly problem in webkit/blink) - beware of overusing layers / 3d transforms!
Fast Forward 24 years
- Vulkan, successor to OpenGL
- very low level access to GPUs
- (excuse me, I’m no expert here)
- based around command buffers
- create on multiple threads
- reuse/recycle
- retained mode:
- reuse objects/buffers, just change small parameters
Servo / Webrender
- retained mode drawing for the web
- renders the web similar to a video game
- can achieve up to 600 fps for certain use cases
> Finished release [optimized] target(s) in 3339.87 secs
> Build Completed in 0:58:35
fml, I need new hardware
Servo / Webrender
- https://air.mozilla.org/bay-area-rust-meetup-february-2016/
- bottleneck moves up one layer
- certain benchmarks show CSSOM/restyling as bottleneck
// yes, this kind of code:
elem.style.top = `${ 10 }px`;
elem.style.left = `${ 10 }px`;
- serializing and parsing strings shows up in profiles
- "immediate mode": throw away previous position, parse string into fresh object.
Mozilla actually announced Quantum yesterday, to integrate Webrender into Firefox
Typed CSS OM
- https://drafts.css-houdini.org/css-typed-om-1/
- avoids serialization / parsing overhead
- still immutable api though
The Problem with JS though
s/computer software industry/js developers/
s/computer hardware industry/browser vendors/
React
http://staltz.com/nothing-new-in-react-and-flux-except-one-thing.html
“The Virtual DOM allows us to convert a mutable retained mode graphics API to an immutable functional immediate mode API.”
Animated (React-Native)
https://speakerdeck.com/vjeux/react-rally-animated-react-performance-toolbox
TLDR: resorts to direct dom manipulation
If I read the React-Native changelog right, they even moved Animated to native code
Immutable/Fractal Architecture
The Elm Architecture; Redux;
Other Immutable Languages / Architectures
You have to basically treat your frontend domain model like a relational database --> Normalize your model!
http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
Ye, so what?
// your state looks like this:
// ---
const initialState = {
contentById: {},
publisherById: {},
pageByUrl: {},
fontByUrl: {},
};
// ---
// and then: (ye, I know this is suboptimal)
// ---
// copy all the hashmaps so we can mutate them in-place
state = Object.assign({}, state, {
contentById: Object.assign({}, state.contentById),
publisherById: Object.assign({}, state.publisherById),
pageByUrl: Object.assign({}, state.pageByUrl),
fontByUrl: Object.assign({}, state.fontByUrl),
});
// ---
// and you have ugly code like this:
// ---
<Collection key={id} collection={item} entities={entities} />
// ---
Selectors
Components "select" data they want inside `connect` (when using react-redux)
"select" sounds kind of like sql…
and you are more or less writing a sql join equivalent
depending on the implementation, you are also creating new objects, defeating the whole purpose of sCU
How About Elm?
Conclusion
the JS ecosystem is changing rapidly,
causing fatigue *huehue*
very strong influence from the
purely functional programming camp
still unsolved problems around
performance and developer productivity (boilerplate)
remember:
JS has no zero cost abstractions
your users will feel every layer of abstraction you add
State to Screen
By Arpad Borsos
State to Screen
How Browsers Render, and why JS devs are making it worse.
- 1,565