bhauman / bhauman.github.com

My blog
http://rigsomelight.com
12 stars 9 forks source link

todos-async/ex4.cljs: "Add Task" button works intermittently #3

Closed rigdern closed 8 years ago

rigdern commented 10 years ago

The more times you click "Add Task" and close the dialogue, the more clicks it takes for the "Add Task" button to register your click and open the dialogue.

The problem is in filter-chan. Each time the dialogue is closed, a new filter-chan is created (thru filter-msg) on input-chan.

Consequently, the old filter-chans still exist and they are all trying to take from input-chan. When clicking "Add Task", one of the old filter-chans may take the click from input-chan preventing the current filter-chan from seeing it and thus preventing the dialogue from appearing. The dialogue only appears when the current filter-chan happens to be the one that takes the click from input-chan.

To fix this, filter-chan should exit when finding the first value that matches the predicate. Here's the a working implementation:

(defn filter-chan [pred channel]
  (let [rc (chan)]
    (go (loop []
          (let [val (<! channel)]
            (if (pred val)
                (put! rc val)
                ;; This recur now only runs in the else case
                (recur)))
          ))
    rc))

Additionally, you may want to give filter-chan an appropriate name to match its new behavior. Perhaps some-chan since it's behavior is now more similar to the behavior of some than filter.

bhauman commented 10 years ago

Hey thanks! I have been to polish that post up a bit to reflect my new understanding of core.asnyc.

I think you have given me the motivation I need.

On Dec 9, 2013, at 12:47 PM, rigdern notifications@github.com wrote:

The more times you click "Add Task" and close the dialogue, the more clicks it takes for the "Add Task" button to register your click and open the dialogue.

The problem is in filter-chan. Each time the dialogue is closed, a new filter-chan is created (thru filter-msg) on input-chan.

Consequently, the old filter-chans still exist and they are all trying to take from input-chan. When clicking "Add Task", one of the old filter-chans may take the click from input-chan preventing the current filter-chan from seeing it and thus preventing the dialogue from appearing. The dialogue only appears when the current filter-chan happens to be the one that takes the click from input-chan.

To fix this, filter-chan should exit when finding the first value that matches the predicate. Here's the a working implementation:

(defn filter-chan [pred channel](let [rc %28chan%29] %28go %28loop [] %28let [val %28<! channel%29] %28if %28pred val%29 %28put! rc val%29 ;; This recur now only runs in the else case %28recur%29%29%29 %29%29 rc)) Additionally, you may want to give filter-chan an appropriate name to match its new behavior. Perhaps some-chan since it's behavior is now more similar to the behavior of some than filter.

— Reply to this email directly or view it on GitHub.

rigdern commented 10 years ago

:)

The bug doesn't repro on your live site but I was able to repro it on a local build. Perhaps one of the dependencies changed since you last generated the post.

If you haven't already seen Rich Hickey's presentation about core.async, you should check it out. It was just posted a few weeks ago.

bhauman commented 10 years ago

Hey I just wanted to let you know that I finally updated the blog post. And I ended up using a some like function as you suggested. So thanks for pointing it out.

When I finally go back to it, it was pretty obvious how off the code was, whew! Anyway I am contemplating doing a core.async patterns and anti patterns post next.

There are few things that are easy to do wrong, most of them have to do with closing channels, and there are several obvious usage patterns.

Thanks again and hope you are having a great holiday.