如果您在Safari连接时快速将表单输入到浏览器REPL中,它最终会失败(通常在20个表单内,有时在100个表单内),Safari会显示
加载资源失败:网络连接已丢失。
此时,评估表单的响应不会发送回终端REPL,而终端REPL将阻止等待永远无法实现的承诺
"main" #1 prio=5 os_prio=31 tid=0x00007fa680011800 nid=0x2603 waiting on condition [0x000070000ad7c000]
java.lang.Thread.State: WAITING (parking)
at jdk.internal.misc.Unsafe.park(
[email protected]/Native Method)
- parking to wait for <0x000000070ad0c030> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.park(
[email protected]/LockSupport.java:194)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(
[email protected]/AbstractQueuedSynchronizer.java:871)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(
[email protected]/AbstractQueuedSynchronizer.java:1024)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(
[email protected]/AbstractQueuedSynchronizer.java:1331)
at java.util.concurrent.CountDownLatch.await(
[email protected]/CountDownLatch.java:232)
at clojure.core$promise$reify__8144.deref(core.clj:7029)
at clojure.core$deref.invokeStatic(core.clj:2312)
at clojure.core$deref.invoke(core.clj:2298)
at cljs.repl.browser$browser_eval.invokeStatic(browser.clj:261)
at cljs.repl.browser$browser_eval.invoke(browser.clj:250)
at cljs.repl.browser.BrowserEnv._evaluate(browser.clj:330)
at cljs.repl$evaluate_form.invokeStatic(repl.cljc:546)
at cljs.repl$evaluate_form.invoke(repl.cljc:480)
at cljs.repl$eval_cljs.invokeStatic(repl.cljc:665)
at cljs.repl$eval_cljs.invoke(repl.cljc:658)
at cljs.repl$repl_STAR_$read_eval_print__6488.invoke(repl.cljc:950)
at cljs.repl$repl_STAR_$fn__6494$fn__6503.invoke(repl.cljc:994)
at cljs.repl$repl_STAR_$fn__6494.invoke(repl.cljc:993)
at cljs.compiler$with_core_cljs.invokeStatic(compiler.cljc:1285)
at cljs.compiler$with_core_cljs.invoke(compiler.cljc:1274)
at cljs.repl$repl_STAR_.invokeStatic(repl.cljc:953)
at cljs.repl$repl_STAR_.invoke(repl.cljc:832)
at cljs.cli$repl_opt.invokeStatic(cli.clj:258)
at cljs.cli$repl_opt.invoke(cli.clj:247)
at cljs.cli$main.invokeStatic(cli.clj:577)
at cljs.cli$main.doInvoke(cli.clj:564)
at clojure.lang.RestFn.invoke(RestFn.java:410)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invokeStatic(core.clj:659)
at clojure.core$apply.invoke(core.clj:652)
at cljs.main$_main.invokeStatic(main.clj:61)
at cljs.main$_main.doInvoke(main.clj:52)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.core$apply.invokeStatic(core.clj:657)
at clojure.main$main_opt.invokeStatic(main.clj:317)
at clojure.main$main_opt.invoke(main.clj:313)
在 main.java:424 的 clojure.main$main.invokeStatic 中
在 main.java:387 的 clojure.main$main.doInvoke 中
在 clojure.lang.RestFn.java:137 的 clojure.lang.RestFn.applyTo 中
at clojure.lang.Var.applyTo(Var.java:702)
在 main.java:37 的 clojure.main.main 中
此问题在 Safari 技术预览版中也可以重现,但在 Chrome 或 Firefox 中不能
重现问题的方法之一是创建一个每行一个表达式的文件(例如,一个整数列表),并将该文件使用 {{cat}} 命令传送到 REPL
cat forms.txt | clj -m cljs.main -ro '{:launch-browser false}' -r
然后使用 Safari 连接到 https://127.0.0.1:9000
另一种重现错误的方法是使用程序驱动 REPL。以下是在 Clojure REPL 中可执行的程序之一
(require '[clojure.java.io :as io])
(let [cmd ["clj" "-m" "cljs.main" "-ro" "{:launch-browser false}" "-r"]
proc (.exec (Runtime/getRuntime) (into-array cmd))
out (.getInputStream proc)
err (.getErrorStream proc)
in (.getOutputStream proc)]
(future (io/copy out *out*))
(future (io/copy err *err*))
(loop [n 0]
(io/copy (io/input-stream (.getBytes (str "(inc " n ")\n"))) in)
(io/copy (io/input-stream (.getBytes (str "(.log js/console " n ")\n"))) in)
(.flush in)
(Thread/sleep (+ 100 (rand-int 200)))
(recur (inc n))))
然后使用 Safari 连接到 https://127.0.0.1:9000
上述程序包括了 JavaScript 控制台日志记录,因此您可以在浏览器控制台中看到计数直到失败的增加
有趣的是,如果我们取消 {{Content-Length}} 头部的注释,则问题就会消失
https://github.com/clojure/clojurescript/blob/7aca40c4b6131b8e08153809a410c06bdfa567ab/src/main/clojure/cljs/repl/server.clj#L166
这灵感来自于 Safari 处理此头的描述,以及它如何产生所看到的错误
https://apple.stackexchange.com/a/107868
注意,这与新的 gzip 代码无关;我尝试禁用 gzip 功能,并在禁用时问题仍然存在。