State to Screen

why JS can’t get to 60 fps

– Arpad „Swatinem“ Borsos –

http://slides.com/swatinem/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

// 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

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,564