When to Consider Reactive Streams


Was implementing reactive streams for Lispz worth the effort? Let’s see where we stand. Let’s consider the example from the last blog post.

(using [message]
  (cascade
    (=> (dom.click "my-message-address" document.body))
    (=> (message.map      @    "mouse"    (=> {x: @.clientX  y: @.clientY})))
    (=> (message.filter      @ "top-left" (=> (< @.x @.y))))
    (=> (message.throttle @ 2000))
    (=> (message.listen   @ (=> (console.log @.x @.y))))
  )
)

If we did not have message streams, the code would look something like:

(document.body.addEventListener "click" (lambda [event]
  (ref data (stateful { last-time: 0 }))
  (ref loc { x: event.clientX, y: event.clientY })
  (cond (< loc.x loc.y) (do
    (ref now (Date))
    (cond ((> data.last-time (+ now 2000)))
      (data.update! { last-time: now })
      (console.log loc.x loc.y)
    )
  ))
))

Well, I guess that answers that. Reactive streams are a lot more readable than in-line code. In addition you are not rewriting throttle every time you need it.

Perhaps I should have asked the question “When don’t we use Reactive Streams for asynchronous events“.

  1. When a promise will do – so any server request that does not need to send a message.
  2. When a stream will have more than one source, or wait on a promise. The current architecture doesn’t merge asynchronous events (yet).

Ok, that is a shorter list thank I expected. Can you think of others? It seems to me that streams work well for continuous discrete data flows from callbacks and events.

Leave a comment