mirror of
https://github.com/status-im/reagent.git
synced 2025-02-03 07:33:24 +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)
|
(let [start-time (atom nil)
|
||||||
render-time (atom nil)
|
render-time (atom nil)
|
||||||
now #(.now js/Date)
|
now #(.now js/Date)
|
||||||
start (fn [] (reset! start-time (now)) nil)
|
start #(reset! start-time (now))
|
||||||
stop #(reset! render-time (- (now) @start-time))
|
stop #(reset! render-time (- (now) @start-time))
|
||||||
timed-f (with-meta f
|
timed-f (with-meta f
|
||||||
{:get-initial-state start
|
{:component-will-mount start
|
||||||
:component-will-update start
|
:component-will-update start
|
||||||
:component-did-mount stop
|
:component-did-mount stop
|
||||||
:component-did-update stop})]
|
:component-did-update stop})]
|
||||||
@ -29,9 +29,8 @@
|
|||||||
(def random-colors (atom nil))
|
(def random-colors (atom nil))
|
||||||
|
|
||||||
(defn to-rgb [{:keys [red green blue]}]
|
(defn to-rgb [{:keys [red green blue]}]
|
||||||
(let [hex (fn [x]
|
(let [hex #(str (if (< % 16) "0")
|
||||||
(str (if (< x 16) "0")
|
(-> % js/Math.round (.toString 16)))]
|
||||||
(-> x js/Math.round (.toString 16))))]
|
|
||||||
(str "#" (hex red) (hex green) (hex blue))))
|
(str "#" (hex red) (hex green) (hex blue))))
|
||||||
|
|
||||||
(defn tweak-color [{:keys [red green blue]}]
|
(defn tweak-color [{:keys [red green blue]}]
|
||||||
@ -44,21 +43,19 @@
|
|||||||
(repeatedly #(-> @base-color tweak-color to-rgb))))
|
(repeatedly #(-> @base-color tweak-color to-rgb))))
|
||||||
|
|
||||||
(defn color-choose [{color-part :color-part}]
|
(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
|
[:input {:type "range" :min 0 :max 255
|
||||||
:style {:width "100%"}
|
|
||||||
:value (color-part @base-color)
|
:value (color-part @base-color)
|
||||||
:on-change
|
:on-change (fn [e]
|
||||||
(fn [e]
|
(swap! base-color assoc
|
||||||
(swap! base-color assoc
|
color-part (-> e .-target .-value int))
|
||||||
color-part (-> e .-target .-value int))
|
(reset-random-colors))}]])
|
||||||
(reset-random-colors))}]])
|
|
||||||
|
|
||||||
(defn ncolors-choose []
|
(defn ncolors-choose []
|
||||||
[:div
|
[:div.color-slider
|
||||||
"number of colors " @ncolors
|
"number of color divs " @ncolors
|
||||||
[:input {:type "range" :min 0 :max 500
|
[:input {:type "range" :min 0 :max 500
|
||||||
:style {:width "100%"}
|
|
||||||
:value @ncolors
|
:value @ncolors
|
||||||
:on-change #(reset! ncolors (-> % .-target .-value))}]])
|
:on-change #(reset! ncolors (-> % .-target .-value))}]])
|
||||||
|
|
||||||
@ -91,16 +88,101 @@
|
|||||||
[timing-wrapper {:component-fn palette}]]))
|
[timing-wrapper {:component-fn palette}]]))
|
||||||
|
|
||||||
(defn main []
|
(defn main []
|
||||||
[:div.reagent-demo
|
(let [om-article {:href "http://swannodette.github.io/2013/12/17/the-future-of-javascript-mvcs/"}]
|
||||||
[title "Reagent: Faster by waiting"]
|
[:div.reagent-demo
|
||||||
[:h1 [link {:href main} "Faster by waiting"]]
|
[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
|
[:p "Reagent already separates state from components. Now they
|
||||||
:src (src-for
|
are also separated in time."]
|
||||||
[:ns :timing-wrapper :base-color
|
|
||||||
:ncolors :random-colors :to-rgb
|
[:p "From version 0.3.0, changes in application state (as
|
||||||
:tweak-color :reset-random-colors :color-choose
|
represented by " [:code "reagent.core/atom"] "s) are no longer
|
||||||
:ncolors-choose :palette :color-demo])}]])
|
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
|
(swap! page-map assoc
|
||||||
"news/reagent-is-async.html" main)
|
"news/reagent-is-async.html" main)
|
||||||
|
@ -122,6 +122,10 @@ ul.nav > li.brand > a {
|
|||||||
color: #444;
|
color: #444;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.demo-text > ul > li {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
.demo-example {
|
.demo-example {
|
||||||
background-color: #ebebeb;
|
background-color: #ebebeb;
|
||||||
}
|
}
|
||||||
@ -159,6 +163,10 @@ ul.nav > li.brand > a {
|
|||||||
width: 100px;
|
width: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.color-slider > input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.color-samples {
|
.color-samples {
|
||||||
clear: both;
|
clear: both;
|
||||||
padding-top: 0.5em;
|
padding-top: 0.5em;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user