Improve exception-handling in reactions

Make sure exceptions in children of reactions don't end up
being caught in the reaction itself.
This commit is contained in:
Dan Holmsand 2016-05-01 13:09:12 +02:00
parent e31c72670c
commit e128117788
3 changed files with 58 additions and 16 deletions

View File

@ -140,7 +140,7 @@
(if (nil? rat)
(ratom/run-in-reaction #(do-render c) c "cljsRatom"
batch/queue-render rat-opts)
(._run rat))))))})
(._run rat false))))))})
(defn custom-wrapper [key f]
(case key

View File

@ -108,7 +108,7 @@
(when-not (nil? q)
(set! rea-queue nil)
(dotimes [i (alength q)]
(._try-run (aget q i)))
(._queued-run (aget q i)))
(recur)))))
(set! batch/ratom-flush flush!)
@ -379,7 +379,7 @@
(set! dirty? true)
(rea-enqueue this))
(if (true? auto-run)
(._run this)
(._run this false)
(auto-run this)))))
(_update-watching [this derefed]
@ -391,20 +391,24 @@
(doseq [w (s/difference old new)]
(-remove-watch w this))))
(_try-run [this]
(_queued-run [this]
(when (and dirty? (some? watching))
(try
(set! caught nil)
(._run this)
(catch :default e
(set! state e)
(set! caught e)
(set! dirty? false)
(notify-w this e nil)))))
(._run this true)))
(_run [this]
(_try-capture [this f]
(try
(set! caught nil)
(deref-capture f this)
(catch :default e
(set! state e)
(set! caught e)
(set! dirty? false))))
(_run [this check]
(let [oldstate state
res (deref-capture f this)]
res (if check
(._try-capture this f)
(deref-capture f this))]
(when-not nocache?
(set! state res)
;; Use = to determine equality from reactions, since
@ -427,7 +431,7 @@
IRunnable
(run [this]
(flush!)
(._run this))
(._run this false))
IDeref
(-deref [this]
@ -445,7 +449,7 @@
(do
(notify-deref-watcher! this)
(when dirty?
(._run this)))))
(._run this false)))))
state)
IDisposable

View File

@ -371,3 +371,41 @@
(is (= @count 3))
(dispose r)
(is (= runs (running)))))
(deftest exception-side-effect
(let [runs (running)
state (r/atom {:val 1})
rstate (reaction @state)
spy (atom nil)
r1 (run! @rstate)
r2 (let [val (reaction (:val @rstate))]
(run!
(reset! spy @val)
(is (some? @val))))
r3 (run!
(when (:error? @rstate)
(throw (js/Error. "Error detected!"))))]
(swap! state assoc :val 2)
(r/flush)
(swap! state assoc :error? true)
(is (thrown? :default (r/flush)))
(r/flush)
(r/flush)
(dispose r1)
(dispose r2)
(dispose r3)
(is (= runs (running)))))
(deftest exception-reporting
(let [runs (running)
state (r/atom {:val 1})
rstate (reaction (:val @state))
r1 (run!
(assert (not= @rstate 13) "fail"))]
(swap! state assoc :val 13)
(is (thrown? :default
(r/flush)))
(swap! state assoc :val 2)
(r/flush)
(dispose r1)
(is (= runs (running)))))