我有一个使用
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
已经完成......我不知道如何解决这...
试试这个:
(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 如何返回结果?- 是的,它是异步的。我看到两种可能性:
clojure.core.async
.经过大量阅读,我使用 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) ""))}])
我添加了命名空间,因为令我惊讶的是回调机制甚至可以跨命名空间工作。好吧,也许这不应该让我感到惊讶;但我正在学习,对我来说是一个新概念。 :)
我回答我的问题以防它对其他人有用(这让我付出了很多!:))
我正在看这个问题,以了解如何使用
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))))))