|
76 | 76 | (doseq [[_ sub] @sub-cache] |
77 | 77 | (dispose! sub))) |
78 | 78 |
|
| 79 | +(defonce ^:private listeners-state |
| 80 | + (atom {:counter 0 :pending '()})) |
| 81 | + |
| 82 | +(defn- invoke-listener |
| 83 | + "This function is responsible for ensuring that signal listeners |
| 84 | + (from DynamicSubs) are called before triggering regular listeners |
| 85 | + (eg: added via use-sub hook). This will ensure that there's only |
| 86 | + a single render per db update." |
| 87 | + [listener-key listener-fn] |
| 88 | + (swap! listeners-state (fn [state] |
| 89 | + (cond-> (update state :counter inc) |
| 90 | + (not (signal? listener-key)) |
| 91 | + (update :pending conj [listener-key listener-fn])))) |
| 92 | + |
| 93 | + (when (signal? listener-key) |
| 94 | + (listener-fn)) |
| 95 | + |
| 96 | + (interop/next-tick |
| 97 | + (fn [] |
| 98 | + (let [listener-fns (atom '())] |
| 99 | + (swap! listeners-state (fn [state] |
| 100 | + (let [{:keys [counter pending] :as new-state} |
| 101 | + (update state :counter dec)] |
| 102 | + (if (zero? counter) |
| 103 | + (do |
| 104 | + (reset! listener-fns pending) |
| 105 | + (assoc new-state :pending '())) |
| 106 | + new-state)))) |
| 107 | + |
| 108 | + ;; ensure listeners are triggered in the order they are registered |
| 109 | + (doseq [[_ f] (sort-by first @listener-fns)] |
| 110 | + (f)))))) |
| 111 | + |
79 | 112 | (deftype Listeners [^:mutable listeners] |
80 | 113 | Object |
81 | 114 | (empty? [_] (empty? listeners)) |
|
84 | 117 | (remove [_ k] |
85 | 118 | (set! listeners (dissoc listeners k))) |
86 | 119 | (notify [_] |
87 | | - (doseq [[_ f] listeners] |
88 | | - (f)))) |
| 120 | + (doseq [[k f] listeners] |
| 121 | + (invoke-listener k f)))) |
89 | 122 |
|
90 | 123 | (defn- make-listeners [] |
91 | 124 | (Listeners. nil)) |
|
0 commit comments