В чем преимущество core.async в clojurescript?

Все говорят о том, насколько хорош core.async и как он улучшит обработку событий в clojurescript. Я следил за руководством по ClojureScript 101 и не вижу явного преимущества из этих примеров кода. Что мне не хватает?

Почему здесь лучше использовать core.async?

(defn listen [el type]
  (let [out (chan)]
    (events/listen el type
      (fn [e] (put! out e)))
    out))

(defn dosomethingasync
  [e]
  (js/console.log "async: " e))

(let [clicks (listen (dom/getElement "search1") "click")]
  (go (while true (dosomethingasync (<! clicks)))))

vs.

(defn dosomethingcallback
   [e]
   (js/console.log "callback: " e))

(events/listen (dom/getElement "search2") "click" dosomethingcallback)

person Imogen    schedule 18.02.2014    source источник
comment
Другой хороший ресурс! infoq.com/interviews/baldridge-core-async   -  person tangrammer    schedule 25.02.2014


Ответы (1)


Отличный вопрос!

Думаю, первым шагом к пониманию преимущества будет видео Тимоти Болдриджа.

И ниже моей попытки:

Я думаю, что различия прояснятся, если мы немного изменим ваш код.

Во-первых, попытаемся выделить предложение "Во всех хороших программах наступает момент, когда компоненты или подсистемы должны перестать напрямую взаимодействовать друг с другом", извлеченное из презентации core.async, размещенной на блог clojure. Я думаю, что мы можем отделить канал входных событий от let fn:

(def clicks (listen (dom/getElement "search1") "click"))

(go
  (while true
    (dosomethingasync (<! clicks))))

(put! clicks "this channel can be written from differents parts of your code")

Во-вторых, с помощью core.async мы можем писать асинхронные вызовы так же, как мы будем писать синхронные вызовы (последовательный код). Пример этой ситуации требует более одного канала:

(def clicks (listen (dom/getElement "search1") "click"))

(def keys-pressed (listen (dom/getElement "search1") "keypress"))

(def to-out (chan))

(go
  (while true
    (let [click-recieved (<! clicks)]
      (dosomethingasync click-recieved)
      (>! to-out "click recieved!")
      (let [other-input-waited (<! keys-pressed)]
        (dosomethingwithkey other-input-waited)
        (>! to-out "keypressed recieved!")
        )
      )
    ))

И, наконец, я думаю, что вы неправильно используете значение функции обратного вызова. Когда мы говорим о функции обратного вызова, я думаю, что мы имеем в виду функцию, которая помимо собственных параметров получает функцию «обратный вызов». В конце выполнения функции мы вызываем функцию обратного вызова, чтобы вернуть поток выполнения в исходную точку. Изменение функции обратного вызова выглядит следующим образом:

(defn dosomethingcallback
   [e call-back-fn]
   (js/console.log "callback: " e)
   (call-back-fn))

И если мы попытаемся выдать что-то похожее на такое же поведение, достигнутое в предыдущем примере кода core.async:

(defn do-key
   [call-back-fn e]
   (.log js/console "before  callback key" )
   (call-back-fn e))

(defn do-click
   [call-back-fn e]
   (.log js/console "before callback click")
   (call-back-fn e))

(defn key-callback-fn [e]
  (.log js/console (str "doing some work with this key: " e))
  )

(defn click-callback-fn [e]
  (.log js/console (str "doing some work with this click" e))
  (events/listen (dom/getElement "search2") "keypress" (partial do-key key-callback-fn)))


  (events/listen (dom/getElement "search2") "click" (partial do-click click-callback-fn))
person tangrammer    schedule 18.02.2014