如何 return FileReader 的结果。在 clojurescript 中

How to return the result of FileReader. in clojurescript

我有一个使用 js/FileReader. 读取文件的函数:

(defn read-file [file]
  (let [js-file-reader (js/FileReader.)]
    (set! (.-onload js-file-reader)
      (fn [evt]
        (let [result (-> evt .-target .-result)
              array (js/Uint8Array. result)]
          {:content array}))) ; <- This is the value that 'read-file' should return
    (.readAsArrayBuffer js-file-reader file)))

问题是我想return.-onload方法的值FileReader,但我只得到(当然)[=的值16=] 自然是 undefined.

非常感谢!

编辑

在尝试 Martin Půda 的回答后,我认为问题与异步的事情有关。我测试了这段代码:

(defn read-file [file]
  (let [js-file-reader (js/FileReader.)
        reading-result (atom)
        done? (atom false)]
    (set! (.-onload js-file-reader)
      (fn [evt]
        (let [result (-> evt .-target .-result)
              array (js/Uint8Array. result)]
          (reset! reading-result {:content array})
          (reset! done? true)
          (js/console.log "in: " (:content @reading-result)))))
    (.readAsArrayBuffer js-file-reader file)
;;     (while (not @done?) (js/console.log (.-readyState js-file-reader)))
    (js/console.log "out: " @reading-result)
    @reading-result))

我得到 first out: undefined 的日志,然后 in: 的日志(与期望的结果)。

当我取消对行 (while...) 的注释时,我得到了 1 的无限循环...所以我认为该函数从未注意到 FileReader 已完成。 ..我不知道怎么解决这个问题...

试试这个:

(defn read-file [file]
  (let [js-file-reader (js/FileReader.)
        reading-result (atom)]
    (set! (.-onload js-file-reader)
      (fn [evt]
        (let [result (-> evt .-target .-result)
              array (js/Uint8Array. result)]
          (reset! reading-result {:content array}))))
    (.readAsArrayBuffer js-file-reader file)
    @reading-result))

请参阅 atom and reset! 的文档。

编辑: 参见 HTML5 FileReader how to return result?- 是的,它是异步的。我看到两种可能性:

  • 您将在事件侦听器中编写所有使用返回值的函数调用。
  • 您将遵循此 CLJS guide for Promises 并使用 JS Promises 或 clojure.core.async

经过大量阅读,我使用 回调 函数解决了这个问题:

(ns lopezsolerluis.fits)

(defn read-file [file callback]
  (let [js-file-reader (js/FileReader.)]
    (set! (.-onload js-file-reader)
      (fn [evt]
        (let [result (-> evt .-target .-result)
              array (js/Uint8Array. result)]
          (callback array))))
    (.readAsArrayBuffer js-file-reader file)))

然后read-file由此调用:

(ns lopezsolerluis.annie-web)

(defn procesar-archivo [result]
  (js/console.log "Bloques: " result))

(defn input-file []
  [:input {:type "file" :id "fits" :name "imagenFits" :accept "image/fits" 
           :on-change (fn [this]
                        (if (not (= "" (-> this .-target .-value)))
                          (let [^js/File file (-> this .-target .-files (aget 0))]
                            (fits/read-file file procesar-archivo)))
                          (set! (-> this .-target .-value) ""))}])

我添加了命名空间,因为令我惊讶的是回调机制甚至可以跨命名空间工作。好吧,也许这不应该让我感到惊讶;但我正在学习,对我来说是一个新概念。 :)

我回答我的问题以防它对其他人有用(这让我付出了很多代价!:))