如何在继续 ClojureScript 中的下一次调用之前等待服务器响应?
How to wait for server response before proceeding to next call in ClojureScript?
(def tables (atom nil))
(defn validateDatasource [datasource]
(get-tables tables)
(js/console.log @tables)
)
(defn get-tables [tables]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler #(reset! tables (vec %))}
))
这里我在单击按钮时调用 validateDatasource 并且 第一次单击时它打印 null..
但是一段时间后,如果我 再次单击它会在控制台中打印表格映射。
因此我想知道如何在继续打印之前等待服务器响应?
ajax/GET
是一个异步调用。这意味着它立即 returns,无需等待服务器的响应。
您可能想要使用 core.async
或者,如果它适合您,流形库。有个port to CLJS.
对你的问题最直接的回答是:你不能在浏览器端等待 javascript 因为 javascript 是严格异步和单线程的。
您的选择是 (1) 编写回调代码,(2) 编写承诺代码,(3) 使用 core.async。
(1) 回调。 不要在服务器上尝试 "wait" 到 return(你不能这样做),而是将代码作为回调:
(defn get-tables [result-atom next]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler (fn [response]
(reset! result-atom (vec response))
(next result-atom))})) ; This is the key line
(defn validate-datasource [datasource]
(js/console.log datasource))
(defn get-and-validate-tables [result-atom]
(get-tables result-atom validate-datasource))
请注意,鉴于您将原子作为参数传递(并隐藏顶级定义),最好完全删除它并让 handler
将响应直接传递给 next
没有弄乱原子。
(2) Promises. 如果你只做一件事,回调很好,但当你试图将多个链接在一起时,它会变得复杂。您可以使用 promesa 库编写使回调更易于处理的承诺代码。
(defn get-tables
[]
(promesa/promise
(fn [resolve reject]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler resolve
:error-handler reject}))))
;; Note, this function returns a promise, so you can call then and catch on it
(get-tables-and-validate []
(-> (get-tables)
(promesa/then (fn [response]
(validate-datasource response)))
(promesa/catch (fn [error]
(js/console.log error)))))
这很好,因为您可以使用对 then
的调用将 promise-returning 调用链接在一起。错误处理也很有效。
3。 Core.async. 您也可以尝试使用 core.async 库,但我会警告您,它引入了很多您可能不需要的复杂性和代码。处理异常也很尴尬,我遇到过极端情况和错误,但没有做任何复杂的事情。在我看来,上面的 promise 代码更健壮,更容易理解。
最后,如果您真的想要原子验证,请注意您可以在原子上使用 set-validator!
。
(set-validator! tables (fn [atm] (validate-datasource atm)))
现在,每当您更新 tables
原子时,验证器都会自动 运行。
(def tables (atom nil))
(defn validateDatasource [datasource]
(get-tables tables)
(js/console.log @tables)
)
(defn get-tables [tables]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler #(reset! tables (vec %))}
))
这里我在单击按钮时调用 validateDatasource 并且 第一次单击时它打印 null.. 但是一段时间后,如果我 再次单击它会在控制台中打印表格映射。
因此我想知道如何在继续打印之前等待服务器响应?
ajax/GET
是一个异步调用。这意味着它立即 returns,无需等待服务器的响应。
您可能想要使用 core.async
或者,如果它适合您,流形库。有个port to CLJS.
对你的问题最直接的回答是:你不能在浏览器端等待 javascript 因为 javascript 是严格异步和单线程的。
您的选择是 (1) 编写回调代码,(2) 编写承诺代码,(3) 使用 core.async。
(1) 回调。 不要在服务器上尝试 "wait" 到 return(你不能这样做),而是将代码作为回调:
(defn get-tables [result-atom next]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler (fn [response]
(reset! result-atom (vec response))
(next result-atom))})) ; This is the key line
(defn validate-datasource [datasource]
(js/console.log datasource))
(defn get-and-validate-tables [result-atom]
(get-tables result-atom validate-datasource))
请注意,鉴于您将原子作为参数传递(并隐藏顶级定义),最好完全删除它并让 handler
将响应直接传递给 next
没有弄乱原子。
(2) Promises. 如果你只做一件事,回调很好,但当你试图将多个链接在一起时,它会变得复杂。您可以使用 promesa 库编写使回调更易于处理的承诺代码。
(defn get-tables
[]
(promesa/promise
(fn [resolve reject]
(ajax/GET "/tables"
{:headers {"Accept" "application/transit+json"}
:handler resolve
:error-handler reject}))))
;; Note, this function returns a promise, so you can call then and catch on it
(get-tables-and-validate []
(-> (get-tables)
(promesa/then (fn [response]
(validate-datasource response)))
(promesa/catch (fn [error]
(js/console.log error)))))
这很好,因为您可以使用对 then
的调用将 promise-returning 调用链接在一起。错误处理也很有效。
3。 Core.async. 您也可以尝试使用 core.async 库,但我会警告您,它引入了很多您可能不需要的复杂性和代码。处理异常也很尴尬,我遇到过极端情况和错误,但没有做任何复杂的事情。在我看来,上面的 promise 代码更健壮,更容易理解。
最后,如果您真的想要原子验证,请注意您可以在原子上使用 set-validator!
。
(set-validator! tables (fn [atm] (validate-datasource atm)))
现在,每当您更新 tables
原子时,验证器都会自动 运行。