I'm trying to make a sleep function in ClojureScript (w/ Reagent):
(ns cljweb.webpage
(:require [reagent.core :as reagent]))
(def temp-atom (reagent/atom 0))
(defn sleep [msec]
(js/setTimeout (fn []) msec))
(defn page []
[:div
[:p @temp-atom]
[:button
{:on-click
(fn []
(sleep 3000)
(swap! temp-atom inc))}
"Click me!"]])
For some reason, this doesn't sleep properly - when I click the "Click me!" button, temp-atom
increments instantly - when I time it, by putting this after in page
:
[:p (time (sleep 3000))]
I get this in the console:
"Elapsed time: 0.015000 msecs"
What did I do wrong in the code?
Javascript's setTimeout
function accepts two arguments: function and timeout in milliseconds. Its contract is to run the received function after the timeout passes.
Your code doesn't pass the function you would like to execute after 3 seconds but instead passes a no-op function ((fn [])
).
Your sleep
function should look like this (and it would be better named timeout
or you could just call js/setTimeout
directly in your on-click handler):
(defn sleep [f ms]
(js/setTimeout f ms))
You also need to change how you call this function:
(sleep #(swap! temp-atom inc) 3000)
Or with calling js/setTimeout
directly:
(js/setTimeout #(swap! temp-atom inc) 3000)
With ClojureScript, the best way to write asynchronous code is with the CoreAsync library. In your case, take a look at the timeout function:
(ns cljweb.webpage
(:use-macros [cljs.core.async.macros :only [go]]
(:require [reagent.core :as reagent]
[cljs.core.async :refer [<! timeout]]))
(def temp-atom (reagent/atom 0))
(defn page []
[:div
[:p @temp-atom]
[:button
{:on-click
(fn []
(go
(<! (timeout 3000))
(swap! temp-atom inc)))}
"Click me!"]])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With