Skip to content

Commit

Permalink
Use yield instead of (timeout 0)
Browse files Browse the repository at this point in the history
(timeout 0) resolves to using js/setTimeout which will actually take 4+
msecs in browsers. This is an eternity. The nextTick approach was
proposed by Patrick O'Brien and implemented here.

Docs on nextTick from Closure library:

Fires the provided callbacks as soon as possible after the current JS
execution context. setTimeout(…, 0) takes at least 4ms when called from
within another setTimeout(…, 0) for legacy reasons.

This will not schedule the callback as a microtask (i.e. a task that can
preempt user input or networking callbacks). It is meant to emulate what
setTimeout(_, 0) would do if it were not throttled. If you desire
microtask behavior, use goog.Promise instead.
  • Loading branch information
danielcompton committed Oct 16, 2015
1 parent 3e8f1e1 commit a2e8c09
Showing 1 changed file with 13 additions and 3 deletions.
16 changes: 13 additions & 3 deletions src/re_frame/router.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
(:require [reagent.core :refer [flush]]
[re-frame.handlers :refer [handle]]
[re-frame.utils :refer [warn error]]
[cljs.core.async :refer [chan put! <! timeout]]))
[cljs.core.async :refer [chan put! <! timeout close!]]
[goog.async.nextTick]))

;; -- The Event Conveyor Belt --------------------------------------------------------------------
;;
Expand All @@ -25,7 +26,7 @@
;; In a perpetual loop, read events from "event-chan", and call the right handler.
;;
;; Because handlers occupy the CPU, before each event is handled, hand
;; back control to the browser, via a (<! (timeout 0)) call.
;; back control to the browser, via a (<! (yield)) call.
;;
;; In some cases, we need to pause for an entire animationFrame, to ensure that
;; the DOM is fully flushed, before then calling a handler known to hog the CPU
Expand All @@ -34,13 +35,22 @@
;; (dispatch ^:flush-dom [:event-id other params])
;;

(defn yield
"Yields control to the browser. Faster than (timeout 0).
See http://dev.clojure.org/jira/browse/ASYNC-137"
[]
(let [ch (chan)]
(goog.async.nextTick #(close! ch))
ch))


(defn router-loop
[]
(go-loop []
(let [event-v (<! event-chan) ;; wait for an event
_ (if (:flush-dom (meta event-v)) ;; check the event for metadata
(do (flush) (<! (timeout 20))) ;; wait just over one annimation frame (16ms), to rensure all pending GUI work is flushed to the DOM.
(<! (timeout 0)))] ;; just in case we are handling one dispatch after an other, give the browser back control to do its stuff
(<! (yield)))] ;; just in case we are handling one dispatch after an other, give the browser back control to do its stuff
(try
(handle event-v)

Expand Down

0 comments on commit a2e8c09

Please sign in to comment.