I'm trying to pass a clojurescript map to a webworker. Before I pass it, it is of type PersistentArrayMap.

cljs.core.PersistentArrayMap {meta: null, cnt: 3, arr: Array(6), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951…}

However, when it gets to the worker, it's just a plain old Object

Object {meta: null, cnt: 3, arr: Array(6), __hash: null, cljs$lang$protocol_mask$partition0$: 16647951…}

with the data seemingly intact. At this point I'd like to turn it back into a PersistentArrayMap so that I can work with it in cljs again.

Using clj->js and js->clj doesn't really work because it doesn't distinguish between keywords and strings, so some data is lost.

What's the best way to handle this situation? It's possible that I'm going about this in the entirely wrong way.

2

There are 2 best solutions below

1
On

Did you use keywordize-keys in the code?

(def json "{\"foo\": 1, \"bar\": 2, \"baz\": [1,2,3]}")
(def a (.parse js/JSON json))
;;=> #js {:foo 1, :bar 2, :baz #js [1 2 3]}

(js->clj a)
;;=> {"foo" 1, "bar" 2, "baz" [1 2 3]}

(js->clj a :keywordize-keys true)
;;=> {:foo 1, :bar 2, :baz [1 2 3]}

Full documentation is here.

0
On

The built-in solution is to serialize the data to EDN and reading it back. clj->js is inherently lossy and should be avoided.

You start by turning the object into a string and send that over to the worker.

(pr-str {:a 1})
;; => "{:a 1}"

In the worker you read it back via cljs.reader/read-string

(cljs.reader/read-string "{:a 1}")
;; => {:a 1}

This will usually be good enough but the transit-cljs library will be slightly faster. Depending on the amount of data you plan on sending it may be worth the extra dependency.