我试图在ClojureScript中创建一个睡眠功能(带有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!"]])
出于某种原因,当我点击"点击我!"按钮,temp-atom
立即递增 - 当我计时时,将其放在page
之后:
[:p (time (sleep 3000))]
我在控制台中得到了这个:
"Elapsed time: 0.015000 msecs"
我在代码中做错了什么?
答案 0 :(得分:10)
Javascript的setTimeout
函数接受两个参数:function和timeout(以毫秒为单位)。它的合同是在超时通过后运行接收的函数。
您的代码在3秒后没有传递您想要执行的函数,而是传递了无操作函数((fn [])
)。
您的sleep
函数应如下所示(最好将其命名为timeout
,或者您可以直接在点击处理程序中调用js/setTimeout
):
(defn sleep [f ms]
(js/setTimeout f ms))
您还需要更改调用此函数的方式:
(sleep #(swap! temp-atom inc) 3000)
或直接致电js/setTimeout
:
(js/setTimeout #(swap! temp-atom inc) 3000)
答案 1 :(得分:9)
使用ClojureScript,编写异步代码的最佳方法是使用CoreAsync库。在您的情况下,请查看timeout函数:
(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!"]])
答案 2 :(得分:0)
有一种方法可以使用goog.async.Debouncer
来实现这种功能这里是一个例子:
(ns example.utils
(:require [goog.async.Debouncer]))
(defn debounce [f interval]
(let [dbnc (goog.async.Debouncer. f interval)]
(fn [& args] (.apply (.-fire dbnc) dbnc (to-array args)))))
(defn save-input! [input]
(js/console.log "Saving input" input))
(def save-input-debounced!
(debounce save-input! 3000))
(save-input-debounced! "hi")