如何在ClojureScript中使用`setTimeout`?

时间:2017-03-31 07:10:41

标签: clojure clojurescript reagent

我试图在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"

我在代码中做错了什么?

3 个答案:

答案 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")