如何在ClojureScript中使用`setTimeout`?

8
我正在尝试在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个回答

16
Javascript的setTimeout函数接受两个参数:函数和毫秒级的超时时间。它的作用是在超时时间过后执行传入的函数。
您的代码没有传递您想要在3秒后执行的函数,而是传递了一个空操作函数((fn []))。
您的sleep函数应该像这样(最好将其命名为timeout,或者您可以直接在on-click处理程序中调用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)

2
嗯...有没有一种方法可以在不使用setTimeout的情况下实现sleep?这是我的主要目标。虽然我可能需要发布一个新问题,但我相当确定这使我的问题成为了XY问题。 - Qwerp-Derp
2
setTimeout有什么问题?请查看https://dev59.com/jnNA5IYBdhLWcg3wdtpd#39914235。 - Piotrek Bzdyl
啊哦...我看到了那个问题的结果,有点令人失望。为了实际实现最新解决方案,我必须安装另一个库,这真是糟糕。不管怎样,还是谢谢! - Qwerp-Derp

10

使用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!"]])

3
我必须说这不是最好的方法。语言中有几种处理异步代码的方式。不同的任务需要不同的工具。在这种情况下,core.async 是过度使用了。另外,它应该是 core.async 而不是 CoreAsync。 - Nek
@Nek,根据您的意见,在这种情况下最好的方法是什么? - Uchiha Itachi
这是setTimeout。 - Nek

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接