core-async

robert-stuttaford 2023-01-16T08:09:09.824739Z

if i use a buffered chan as a queue - is it somehow possible to detect that the chan has more items in the buffer, when processing a take? use-case is we're using a chan to linearise events in clojurescript in a browser, to ensure that state updates are strictly "single threaded". it'd be great to detect that there are multiple events queued, so that we can process them all before updating state, rather than updating state once per event. i ask because it may be that core.async isn't designed for this, and this isn't possible. hoping to benefit from some more knowledgeable / experienced folks 🙂

phronmophobic 2023-01-16T08:20:25.794929Z

It seems like poll! should work for this.

phronmophobic 2023-01-16T08:21:13.917789Z

or are you trying to determine if there are more items without actually consuming them from the channel?

robert-stuttaford 2023-01-16T08:27:18.612649Z

basically, when processing the next take, i'd like to soak up all buffered items at that time and process them. it may be that what i want isn't actually possible because of the single-threaded nature of js, and what i actually need is timer tick to check for and process whatever's queued, and not use async at all!

robert-stuttaford 2023-01-16T08:27:24.000429Z

thanks for the response 🙂

phronmophobic 2023-01-16T08:30:51.629009Z

yea, I think something like the following should work

(go
  (loop []
    (let [;; wait for something
          x (<! ch)
          ;; consume until there's nothing left
          batch (loop [batch [x]]
                  (let [x (poll! ch)]
                    (if x
                      (recur (conj batch x))
                      batch)))]
      (process batch))
    (recur)))

phronmophobic 2023-01-16T08:32:02.779569Z

you can also add timeouts to allow for more batching

robert-stuttaford 2023-01-16T08:32:15.394029Z

nice i'm going to experiment with that, thanks man

robert-stuttaford 2023-01-16T08:33:10.651099Z

re-frame uses a timer it seems https://github.com/day8/re-frame/blob/master/src/re_frame/router.cljc

👍 1
robert-stuttaford 2023-01-16T08:38:07.926289Z

your example looks like it might work! i wonder though, would successive put! actually be processed before the current take, given the single thread? my guess is no. i'll test to find out, and let you know!

phronmophobic 2023-01-16T08:42:58.808909Z

I would also not expect successive puts to arrive in the same batch. for that, I would probably add a short timeout window for grouping multiple values into the same batch

robert-stuttaford 2023-01-16T08:43:07.327619Z

yeah

phronmophobic 2023-01-16T08:45:08.706169Z

if the producer already naturally groups outputs, then you could also batch at that end.

robert-stuttaford 2023-01-16T08:50:21.265829Z

yeah. i thought about that too, but it won't fly; producers are browser events - user clicks and keypresses, xhr callbacks, websocket message callbacks, address changes, etc. we're using core.async to soak and linearise this ad-hoc, unpredictable stream of inputs

👍 1
robert-stuttaford 2023-01-16T10:26:15.514969Z

neat, gonna read, thanks Ben!

robert-stuttaford 2023-01-16T10:28:41.069329Z

JVM Clj only, right, @ben.sless?

Ben Sless 2023-01-16T11:11:05.818139Z

I think the implementation of batch! should work in cljs

robert-stuttaford 2023-01-16T11:45:17.887089Z

cool will check it out