I try to deasync some js-calls using clojure script. If I let the atom in the deasync function itself there is a suprising result:
(let [result (atom nil)
timeout (atom 10)]
(go
(let [async-result (<p! (js/Promise.resolve 42))]
(swap! result (constantly async-result))
(js/console.log @result)))
(while (and (nil? @result)
(pos? @timeout))
(do (debug @result)
(debug @timeout)
(swap! timeout dec)))
@result)
--- output is ---
null
10
...
null
1
42
nil
If I define the atom outside the result is as intended:
(def result (atom nil))
(let [timeout (atom 10)]
(go
(let [async-result (<p! (js/Promise.resolve 42))]
(swap! result (constantly async-result))
(js/console.log @result)))
(while (and (nil? @result)
(pos? @timeout))
(do (debug @result)
(debug @timeout)
(swap! timeout dec)))
@result)
--- output is ---
42
42
Can someone declare the difference? I think using a namespace global atom is not quite a good idea for a deasync function ...
It is not possible to write a "deasync" function, if by that you mean writing a function that "blocks" to wait for an async result. JavaScript is single-threaded so if you block in a loop to wait for an async result that loop will prevent the async work from ever happening.
The result in your program above will always be that it loops 10 times while the result is
niland then eventually yield control to let the queued microtask execute thego.I suspect that you just maybe tried to run this from the REPL and did not redefine the
resultatom after one test run. So in the first pass it wasnilbut then got set to42. On the second run it then starts with 42 and your loop never loops. You can easily verify this by "labeling" your results. So instead of(js/console.log @result)you use(js/console.log "go-result" @result). You'll see that you'll always get the loop result first and then thego-result.BTW if you just want to set a specific
atomvalue just usereset!instead ofswap!withconstantly, eg.(reset! result async-result).