ClojureScript 中回调中的 clearInterval
clearInterval inside callback in ClojureScript
基本上,我想要的是在ClojureScript中实现这段代码:
var win = window.open('foo.html', 'windowName');
var timer = setInterval(function() {
if(win.closed) {
clearInterval(timer);
alert('closed');
}
}, 1000);
我试过这个:
(let [popup (.open js/window "foo.html" "windowName")
interval (.setInterval
js/window
(fn []
(when (.-closed popup)
(do
;; 'interval' is undefined at this point
(.clearInterval js/window interval)
(.alert js/window 'closed')))
1000)]
...)
但是 CLJS 编译器警告我 interval
未定义。
有什么想法吗?
问题是您在定义绑定之前在匿名函数中访问了 interval
本地绑定(在绑定到 interval
符号之前必须先评估右侧,直到那么 interval
未定义。
您可以通过定义一个原子来存储您的间隔并从您的回调函数访问它来解决它:
(let [popup (.open js/window 'foo.html', 'windowName')
interval (atom nil)]
(reset! interval (.setInterval
js/window
(fn []
(when (.-closed popup)
(do
(.clearInterval js/window @interval)
(.alert js/window "Closed")))))))
我不确定是否有更优雅的方法来使用您的间隔回调方法来实现它。
另一种方法是使用直接 js 互操作:
(let [popup (.open js/window "foo.html" "windowName")]
(js* "var interval = setInterval(function() {
if (popup.closed) {
clearInterval(interval);
alert('close');
}
}, 500);")
...)
使用 atom
- 容易
- 并且包含在 ClojureScript 的核心功能中
然而 interval
atom
可能无法清楚地表达其实际性质和意图。
最初的问题是编译器抱怨 未定义 interval
。所以需要的是一个值:
- 可以先定义和
- 已解决(已交付)稍后
对我来说这听起来像是 promise
。从 ClojureScript 1.8.34 Clojure promises aren't supported yet. Because of the existence of core.async there are indications that support of Clojure's promise isn't an urgent priority in ClojureScript - especially as core.async contains promise-chan
开始。使用promise-chan
,代码可以写成如下
(ns test.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [cljs.core.async :refer [<! close! promise-chan put!]]))
(let [interval (promise-chan)
fooWin (.open js/window "./foo.html", "windowName")
checkOnFooWin
(fn []
(when (.-closed fooWin) ;; when has an implicit do
(go
(.clearInterval js/window (<! interval)))
(.alert js/window "Closed")))]
(put! interval (.setInterval js/window checkOnFooWin 500))
(close! interval))
此代码既不比 atom
版本更简单也不优雅 - 但是它确实具有
的优势
interval
只能解决一次
- 从
interval
中获取的每个值将始终是最初提供的值。
基本上,我想要的是在ClojureScript中实现这段代码:
var win = window.open('foo.html', 'windowName');
var timer = setInterval(function() {
if(win.closed) {
clearInterval(timer);
alert('closed');
}
}, 1000);
我试过这个:
(let [popup (.open js/window "foo.html" "windowName")
interval (.setInterval
js/window
(fn []
(when (.-closed popup)
(do
;; 'interval' is undefined at this point
(.clearInterval js/window interval)
(.alert js/window 'closed')))
1000)]
...)
但是 CLJS 编译器警告我 interval
未定义。
有什么想法吗?
问题是您在定义绑定之前在匿名函数中访问了 interval
本地绑定(在绑定到 interval
符号之前必须先评估右侧,直到那么 interval
未定义。
您可以通过定义一个原子来存储您的间隔并从您的回调函数访问它来解决它:
(let [popup (.open js/window 'foo.html', 'windowName')
interval (atom nil)]
(reset! interval (.setInterval
js/window
(fn []
(when (.-closed popup)
(do
(.clearInterval js/window @interval)
(.alert js/window "Closed")))))))
我不确定是否有更优雅的方法来使用您的间隔回调方法来实现它。
另一种方法是使用直接 js 互操作:
(let [popup (.open js/window "foo.html" "windowName")]
(js* "var interval = setInterval(function() {
if (popup.closed) {
clearInterval(interval);
alert('close');
}
}, 500);")
...)
使用 atom
- 容易
- 并且包含在 ClojureScript 的核心功能中
然而 interval
atom
可能无法清楚地表达其实际性质和意图。
最初的问题是编译器抱怨 未定义 interval
。所以需要的是一个值:
- 可以先定义和
- 已解决(已交付)稍后
对我来说这听起来像是 promise
。从 ClojureScript 1.8.34 Clojure promises aren't supported yet. Because of the existence of core.async there are indications that support of Clojure's promise isn't an urgent priority in ClojureScript - especially as core.async contains promise-chan
开始。使用promise-chan
,代码可以写成如下
(ns test.core
(:require-macros [cljs.core.async.macros :refer [go]])
(:require [cljs.core.async :refer [<! close! promise-chan put!]]))
(let [interval (promise-chan)
fooWin (.open js/window "./foo.html", "windowName")
checkOnFooWin
(fn []
(when (.-closed fooWin) ;; when has an implicit do
(go
(.clearInterval js/window (<! interval)))
(.alert js/window "Closed")))]
(put! interval (.setInterval js/window checkOnFooWin 500))
(close! interval))
此代码既不比 atom
版本更简单也不优雅 - 但是它确实具有
interval
只能解决一次- 从
interval
中获取的每个值将始终是最初提供的值。