简体   繁体   English

为什么 let-defined atom 会提供不同的结果?

[英]Why does let-defined atom provide a different result?

I try to deasync some js-calls using clojure script.我尝试使用 clojure 脚本取消同步一些 js 调用。 If I let the atom in the deasync function itself there is a suprising result:如果我让原子在 deasync function 本身有一个令人惊讶的结果:

(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...我认为使用命名空间全局原子对于异步 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.如果您的意思是编写“阻塞”以等待异步结果的 function,则无法编写“deasync” function。 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. JavaScript 是单线程的,因此如果您在循环中阻塞以等待异步结果,该循环将阻止异步工作发生。

The result in your program above will always be that it loops 10 times while the result is nil and then eventually yield control to let the queued microtask execute the go .上面程序中的结果将始终是它循环 10 次,而结果为nil ,然后最终让出控制权让排队的微任务执行go

I suspect that you just maybe tried to run this from the REPL and did not redefine the result atom after one test run.我怀疑您可能只是尝试从 REPL 运行它,并且在一次测试运行后没有重新定义result原子。 So in the first pass it was nil but then got set to 42 .所以在第一遍中它是nil但后来被设置为42 On the second run it then starts with 42 and your loop never loops.在第二次运行时,它从 42 开始,你的循环永远不会循环。 You can easily verify this by "labeling" your results.您可以通过“标记”结果轻松验证这一点。 So instead of (js/console.log @result) you use (js/console.log "go-result" @result) .因此,您使用(js/console.log "go-result" @result)而不是(js/console.log @result) ) 。 You'll see that you'll always get the loop result first and then the go-result .你会看到你总是首先得到循环结果,然后是go-result

BTW if you just want to set a specific atom value just use reset!顺便说一句,如果您只想设置特定的atom值,只需使用reset! instead of swap!而不是swap! with constantly , eg. constantly ,例如。 (reset! result async-result) . (reset! result async-result)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM