Как ждать ответа сервера, прежде чем перейти к следующему вызову в ClojureScript? - PullRequest
0 голосов
/ 13 мая 2018
(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 при нажатии кнопки и при первом щелчке это печатает ноль .. Но через некоторое время, если я снова нажму, этопечать карты таблиц в консоли.

Таким образом, я хочу знать, как я могу дождаться ответа сервера, прежде чем приступить к его печати?

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Самый прямой ответ на ваш вопрос: вы не можете ждать в браузерном javascript, потому что javascript является строго асинхронным и однопоточным.

Вы можете выбрать (1) написать код обратного вызова, (2) написать код обещания, (3) использовать core.async.

(1) Обратные вызовы. Вместо того, чтобы пытаться «ждать» на сервере для возврата (что вы не можете сделать), передайтекод в качестве обратного вызова:

(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) Обещания. Обратные вызовы хороши, если вы делаете только одно, но в тот момент, когда вы пытаетесь соединитьсяболее чем вместе это будет сложно.Вы можете использовать библиотеку 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.Обработка ошибок также работает хорошо.

3.Core.async. Вы также можете попробовать использовать библиотеку core.async, но я предупреждаю вас, что она содержит много сложности и кода, который вам, вероятно, не нужен.Также довольно неудобно иметь дело с исключениями, и я разбираюсь с угловыми случаями и ошибками, не делая ничего такого сложного.По моему мнению, приведенный выше код обещания является более надежным и простым для исполнения.

Наконец, если проверка атома действительно все, что вам нужно, учтите, что вы можете использовать set-validator! для своего атома.

(set-validator! tables (fn [atm] (validate-datasource atm)))

Теперь, когда вы обновляете атом tables, валидатор запускается автоматически.

0 голосов
/ 13 мая 2018

ajax/GET - это асинхронный вызов. Это означает, что он возвращается немедленно, не дожидаясь ответа от сервера.

Возможно, вы захотите использовать core.async или, если вам подходит, библиотеку манифольдов. Существует порт для CLJS .

...