Clojure Channel Event Speed ​​Calculation

I want to calculate the speed of events, for example, key keystroke events and display them. I also want to start calculating the rate only after the first event has occurred. Another requirement is that the speed calculation must stop after a certain number of keypress events. My current approach to this is

(defn keypress-chan
  "Returns a channel that receives keys"
  []
  (let [out (chan) handler (fn [e] (put! out (.-key e)))]
    (js/document.addEventListener "keypress" handler false)
    out))

(defn tick
  "Pushes to `out` 1000 ms later"
  [out]
  (go
    (<! (timeout 1000))
    (>! out 1)))

(defn get-rate
  "Calculates keypress per minute rate"
  [ticks pressed]
  (quot (* pressed 60) ticks))

(defn complete?
  [count]
  (>= count 100))

(defn main-loop []
  (let [key-chan (keypress-chan) ticker-chan (chan)]
    (go-loop [pressed 0 ticks 0]
      (let [[value ch] (alts! [key-chan ticker-chan])]
        (if (= ch key-chan)
          (do
            ;; Start timer to calculate keypress rate
            (if (zero? pressed)
              (tick ticker-chan))

            ;; Do something with `value`, i. e. the key being pressed

            (when-not (complete?)
              (recur (inc pressed) ticks)))

          (let [speed (get-rate ticks pressed)]
            (swap! app-state assoc :rate rate)
            (tick ticker-chan)
            (recur pressed (inc ticks))))))))

So this works, but the code in main-loopit seems to me ugly. I was thinking about having a “trigger” that only fires when the first value appears in key-chanand starts the timer. Then another trigger stops the timer when necessary. But I am new to Clojure and don’t know how to work with async, so I could not create anything better than the code above.

? key-chan? ?

+4
1

.

(ns ratecalc.core
  (:require [cljs.core.async :refer [chan <! go-loop]])
  (:import [goog.date DateTime]))

(defn calc-rate [input-chan do-fun max-count]
  (go-loop [count 0
            start-time nil]
    (<! input-chan)
    (let [inc-count (inc count)
          now (.getTime (DateTime.))
          start-time* (if-not start-time now start-time)
          rate-per-ms (/ inc-count (- now start-time*))]
      (do-fun rate-per-ms)
      (if (= count max-count)
        rate-per-ms
        (recur inc-count start-time*)))))

calc-rate . , , , . . , :

(calc-rate (keypress-chan) println 10)
0

Source: https://habr.com/ru/post/1670705/


All Articles