ClojureScript中如何等待服务器响应后再执行后续调用?
解决异步请求后的时序问题
首先咱们得搞清楚为啥会出现这个情况:ajax/GET是异步执行的——你调用get-tables之后,代码会立刻往下走执行js/console.log @tables,这时候服务器的响应还没回来,tables这个atom还是初始的nil,所以第一次打印null;等你第二次点击的时候,之前的请求已经完成,atom已经被更新成服务器返回的数据,自然就能正常打印了。
要解决这个问题,核心就是等服务器响应回来、atom更新完成之后,再执行打印操作,这里给你几种常用的方案:
方案一:利用Promise链式调用
ajax/GET本身会返回一个JS Promise,我们可以直接用它的.then方法来指定请求完成后要执行的操作:
(def tables (atom nil)) (defn get-tables [] ;; 返回ajax请求的Promise (ajax/GET "/tables" {:headers {"Accept" "application/transit+json"} :handler #(reset! tables (vec %))})) (defn validateDatasource [datasource] ;; 等get-tables的请求完成后再打印 (.then (get-tables) (fn [] (js/console.log @tables))))
方案二:使用async/await(更直观的异步写法)
如果你习惯现代JS的异步风格,可以把validateDatasource定义成async函数,用await等待请求完成:
(def tables (atom nil)) (defn get-tables [] (ajax/GET "/tables" {:headers {"Accept" "application/transit+json"} :handler #(reset! tables (vec %))})) (defn validateDatasource [datasource] (js/async function [] ;; 等待请求完成 (await (get-tables)) ;; 此时atom已经被更新,打印即可 (js/console.log @tables)))
方案三:直接把打印逻辑放到请求的handler里
如果打印操作就是这个请求完成后必须立刻做的事情,那最简单的方式就是把打印逻辑直接写在get-tables的handler里:
(def tables (atom nil)) (defn get-tables [] (ajax/GET "/tables" {:headers {"Accept" "application/transit+json"} :handler (fn [response] (reset! tables (vec response)) ;; 请求完成后立刻打印 (js/console.log @tables))})) (defn validateDatasource [datasource] (get-tables))
这几个方案都能解决你的问题,你可以根据自己的业务场景选最合适的——比如如果后续还要在请求完成后做更多操作,方案一或二更灵活;如果只是单纯打印,方案三最省事。
内容的提问来源于stack exchange,提问作者Debanjan Mondal
相关产品推荐
相关产品推荐

