如何返回FileReader的结果。在 clojurescript

问题描述 投票:0回答:3

我有一个使用

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)))

问题是我希望它返回

.-onload
FileReader
方法的值,但我(当然)只得到
(.readAsArrayBuffer js-file-reader file)
的值,这自然是
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
的日志,然后 then
in:
的日志(具有期望的结果)。

当我取消注释

(while...)
行时,我得到了
1
的无限循环......所以我认为该功能从未注意到
FileReader
已经完成......我不知道如何解决这...

return-value filereader clojurescript
3个回答
0
投票

试试这个:

(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
reset!
的文档。

编辑: 请参阅HTML5 FileReader 如何返回结果?- 是的,它是异步的。我看到两种可能性:

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

0
投票

经过大量阅读,我使用 callback 函数解决了它:

(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) ""))}])

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

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


0
投票

我正在看这个问题,以了解如何使用

promesa
做到这一点。

这是我最终得出的结果,自成一体,只以

file
为参数。

(defn read-file-promise [file]
  (let [callback (fn [cb]
                   (let [fr (js/FileReader.)]
                     (set! (.-onload fr)
                           (fn [evt]
                             (let [result (-> evt .-target .-result)]
                               (cb result))))
                     (set! (.-onerror fr)
                           (fn [err]
                             (log/error "FileReader creation failed, error: " err)))
                     (.readAsText fr file)))]
    (let [prom (p/create
                (fn [resolve _]
                  (callback resolve)))]
      (p/then prom (fn [text] (log/info text))))))

似乎必须在实例化 promise 之前显式定义回调 fn。在 cljs 方面更有经验的人可能会说出原因。

我玩过这种东西,但无法让它工作。

(defn read-file-promise-broken [file]
  (let [prom
        (p/create
         (fn [resolve reject]
           (let [fr (js/FileReader.)]
             (set! (.-onload fr) (fn [evt]
                                   (log/error "This will never be called")
                                   (let [result (-> evt .-target .-result)]
                                     (resolve result))))
             (set! (.-onerror fr) #(do
                                     (log/info "Rejecting FR" fr)
                                     (reject "Could not initialize FileReader")))
             fr)))]
    (p/then prom (fn [fr]
                   (let [output (.readAsText fr file)]
                     (log/info output))))))
© www.soinside.com 2019 - 2024. All rights reserved.