Skip to content

Commit a2e8c09

Browse files
committed
Use yield instead of (timeout 0)
(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.
1 parent 3e8f1e1 commit a2e8c09

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

src/re_frame/router.cljs

+13-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
(:require [reagent.core :refer [flush]]
55
[re-frame.handlers :refer [handle]]
66
[re-frame.utils :refer [warn error]]
7-
[cljs.core.async :refer [chan put! <! timeout]]))
7+
[cljs.core.async :refer [chan put! <! timeout close!]]
8+
[goog.async.nextTick]))
89

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

38+
(defn yield
39+
"Yields control to the browser. Faster than (timeout 0).
40+
See http://dev.clojure.org/jira/browse/ASYNC-137"
41+
[]
42+
(let [ch (chan)]
43+
(goog.async.nextTick #(close! ch))
44+
ch))
45+
46+
3747
(defn router-loop
3848
[]
3949
(go-loop []
4050
(let [event-v (<! event-chan) ;; wait for an event
4151
_ (if (:flush-dom (meta event-v)) ;; check the event for metadata
4252
(do (flush) (<! (timeout 20))) ;; wait just over one annimation frame (16ms), to rensure all pending GUI work is flushed to the DOM.
43-
(<! (timeout 0)))] ;; just in case we are handling one dispatch after an other, give the browser back control to do its stuff
53+
(<! (yield)))] ;; just in case we are handling one dispatch after an other, give the browser back control to do its stuff
4454
(try
4555
(handle event-v)
4656

0 commit comments

Comments
 (0)