mirror of
https://github.com/status-im/reagent.git
synced 2025-02-02 23:23:51 +00:00
Start writing copy about async rendering
This commit is contained in:
parent
e10548f8ba
commit
1c702920bd
@ -12,10 +12,10 @@
|
||||
(let [start-time (atom nil)
|
||||
render-time (atom nil)
|
||||
now #(.now js/Date)
|
||||
start (fn [] (reset! start-time (now)) nil)
|
||||
start #(reset! start-time (now))
|
||||
stop #(reset! render-time (- (now) @start-time))
|
||||
timed-f (with-meta f
|
||||
{:get-initial-state start
|
||||
{:component-will-mount start
|
||||
:component-will-update start
|
||||
:component-did-mount stop
|
||||
:component-did-update stop})]
|
||||
@ -29,9 +29,8 @@
|
||||
(def random-colors (atom nil))
|
||||
|
||||
(defn to-rgb [{:keys [red green blue]}]
|
||||
(let [hex (fn [x]
|
||||
(str (if (< x 16) "0")
|
||||
(-> x js/Math.round (.toString 16))))]
|
||||
(let [hex #(str (if (< % 16) "0")
|
||||
(-> % js/Math.round (.toString 16)))]
|
||||
(str "#" (hex red) (hex green) (hex blue))))
|
||||
|
||||
(defn tweak-color [{:keys [red green blue]}]
|
||||
@ -44,21 +43,19 @@
|
||||
(repeatedly #(-> @base-color tweak-color to-rgb))))
|
||||
|
||||
(defn color-choose [{color-part :color-part}]
|
||||
[:div (name color-part) " " (color-part @base-color)
|
||||
[:div.color-slider
|
||||
(name color-part) " " (color-part @base-color)
|
||||
[:input {:type "range" :min 0 :max 255
|
||||
:style {:width "100%"}
|
||||
:value (color-part @base-color)
|
||||
:on-change
|
||||
(fn [e]
|
||||
(swap! base-color assoc
|
||||
color-part (-> e .-target .-value int))
|
||||
(reset-random-colors))}]])
|
||||
:on-change (fn [e]
|
||||
(swap! base-color assoc
|
||||
color-part (-> e .-target .-value int))
|
||||
(reset-random-colors))}]])
|
||||
|
||||
(defn ncolors-choose []
|
||||
[:div
|
||||
"number of colors " @ncolors
|
||||
[:div.color-slider
|
||||
"number of color divs " @ncolors
|
||||
[:input {:type "range" :min 0 :max 500
|
||||
:style {:width "100%"}
|
||||
:value @ncolors
|
||||
:on-change #(reset! ncolors (-> % .-target .-value))}]])
|
||||
|
||||
@ -91,16 +88,101 @@
|
||||
[timing-wrapper {:component-fn palette}]]))
|
||||
|
||||
(defn main []
|
||||
[:div.reagent-demo
|
||||
[title "Reagent: Faster by waiting"]
|
||||
[:h1 [link {:href main} "Faster by waiting"]]
|
||||
(let [om-article {:href "http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/"}]
|
||||
[:div.reagent-demo
|
||||
[title "Reagent: Faster by waiting"]
|
||||
[:h1 [link {:href main} "Faster by waiting"]]
|
||||
[:div.demo-text
|
||||
[:h2 "Reagent gets async rendering"]
|
||||
|
||||
[demo-component {:comp color-demo
|
||||
:src (src-for
|
||||
[:ns :timing-wrapper :base-color
|
||||
:ncolors :random-colors :to-rgb
|
||||
:tweak-color :reset-random-colors :color-choose
|
||||
:ncolors-choose :palette :color-demo])}]])
|
||||
[:p "Reagent already separates state from components. Now they
|
||||
are also separated in time."]
|
||||
|
||||
[:p "From version 0.3.0, changes in application state (as
|
||||
represented by " [:code "reagent.core/atom"] "s) are no longer
|
||||
immediately rendered to the DOM. Instead, Reagent waits until the
|
||||
browser is ready to repaint the window, and then all the changes
|
||||
are rendered in one single go."]
|
||||
|
||||
[:p "This is good for all sorts of reasons:"]
|
||||
[:ul
|
||||
|
||||
[:li "Reagent doesn't have to spend time doing renderings that
|
||||
no one would ever see (because changes to application state
|
||||
happened faster than the browser could repaint)."]
|
||||
|
||||
[:li "If two or more atoms are changed simultaneously, this now
|
||||
leads to only one re-rendering, and not two."]
|
||||
|
||||
[:li "The new code does proper batching of renderings even when
|
||||
changes to atoms are done outside of event handlers (which is
|
||||
great for e.g core.async users)."]
|
||||
|
||||
[:li "Repaints can be synced by the browser with for example CSS
|
||||
transitions, because Reagent uses requestAnimationFrame to do
|
||||
the batching. That makes for example animations smoother."]]
|
||||
|
||||
[:p "In short, Reagent renders less often, but at the right
|
||||
times. For a much better description of why async rendering is
|
||||
good, see David Nolen’s " [:a om-article "excellent explanation
|
||||
here."]]
|
||||
|
||||
[:h2 "The bad news"]
|
||||
|
||||
[:p "Lunches in general tend to be non-free, and this is no
|
||||
exception… The downside to async rendering is that you can no
|
||||
longer depend on changes to atoms being immediately available in
|
||||
the DOM. (Actually, you couldn’t before either, since React.js
|
||||
itself does batching inside event handlers.)"]
|
||||
|
||||
[:p "This may make testing a bit more verbose: you now have to
|
||||
call " [:code "reagent.core/flush"] " to force Reagent to
|
||||
synchronize state with the DOM."]
|
||||
|
||||
[:h2 "An example"]
|
||||
|
||||
[:p "Here is an example to (hopefully) demonstrate the virtues of
|
||||
async rendering. It consists of a simple color chooser (three
|
||||
sliders to set the red, green and blue components of a base
|
||||
color), and shows the base color + a bunch of divs in random
|
||||
matching colors. As soon as the base color is changed, a new set
|
||||
of random colors is shown."]
|
||||
|
||||
[:p "If you change one of the base color components, the base
|
||||
color should change immediately, and smoothly (on my Macbook Air,
|
||||
rendering takes around 2ms, with 20 colored divs showing)."]
|
||||
|
||||
[:p "But perhaps more interesting is to see what happens when the
|
||||
updates can’t be made smoothly (because the browser simply cannot
|
||||
re-render the colored divs quickly enough). On my machine, this
|
||||
starts to happen if I change the number of divs shown to above
|
||||
150 or so."]
|
||||
|
||||
[:p "As you increase the number of divs, you’ll notice that the
|
||||
base color no longer changes quite so smoothly when you move the
|
||||
color sliders."]
|
||||
|
||||
[:p "But the crucial point is that the sliders " [:strong "still
|
||||
work"] ". Without async rendering, you could quickly get into a
|
||||
situation where the browser hangs for a while, doing updates
|
||||
corresponding to an old state. "]
|
||||
|
||||
[:p "With async rendering, the only thing that happens is that
|
||||
the frame rate goes down."]
|
||||
|
||||
[:p "Btw, I find it quite impressive that React manages to change
|
||||
500 divs (12 full screens worth) in slightly more than 40ms. And
|
||||
even better: when I change the number of divs shown, it only
|
||||
takes around 5ms to re-render the color palette (because the
|
||||
individual divs don’t have to be re-rendered, divs are just added
|
||||
or removed from the DOM as needed)."]]
|
||||
|
||||
[demo-component {:comp color-demo
|
||||
:src (src-for
|
||||
[:ns :timing-wrapper :base-color
|
||||
:ncolors :random-colors :to-rgb
|
||||
:tweak-color :reset-random-colors :color-choose
|
||||
:ncolors-choose :palette :color-demo])}]]))
|
||||
|
||||
(swap! page-map assoc
|
||||
"news/reagent-is-async.html" main)
|
||||
|
@ -122,6 +122,10 @@ ul.nav > li.brand > a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.demo-text > ul > li {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.demo-example {
|
||||
background-color: #ebebeb;
|
||||
}
|
||||
@ -159,6 +163,10 @@ ul.nav > li.brand > a {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.color-slider > input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.color-samples {
|
||||
clear: both;
|
||||
padding-top: 0.5em;
|
||||
|
Loading…
x
Reference in New Issue
Block a user