I'm working with clojurescript and localforage a promise based storage library. I have a structure set up like the following in localstorage as key value pairs
"names" : ["name1","name2","name3"]
Where then each "names" is a key for another set of values.
"name1": [val1,val2,val3]
I'm currently at the point where I have the list of names and now need to iterate through that list, get the values for each one, and then return a map with a format like:
{:name1 [val1,val2,val3] :name2 [val1,val2]}
To accomplish this, I came up with the following snippet:
(defn get-project-dates [project-map]
"Handles getting all the times/dates for project"
(loop [i 0
project-dates {}]
(if (= i (count project-map))
project-dates
(.then (.getItem localforage (nth project-map i)) (fn [promiseVal]
(recur (inc i) (conj project-dates {(key (nth project-map i)) promiseVale})))))))
Unfortunately this doesn't work as instead of recur going to the loop, it will go back to the (fn). This (fn) callback is however required as the (.getItem) call returns a promise that I can't access otherwise.
My question is then is there a way to get that promise value out and recur to the loop, or a better way overall to do this?
There is no way that I know of to pick what you want to recur
into. As far as I know, it's entirely dependant on scope.
You could make it a straight recursive function though. There's a few ways you could set this up:
; Give it two argument lists. The 1-arity version is meant to be called by the user,
; while the 3-arity version is meant for recursive calls
(defn get-project-dates
([project-map i project-dates]
(if (= i (count project-map))
project-dates
(.then (.getItem localforage (nth project-map i))
(fn [promiseVal]
(get-project-dates
project-map
(inc i)
(conj project-dates {(key (nth project-map i)) promiseVale}))))))
([project-map]
(get-project-dates project-map 0 {})))
or
(defn get-project-dates [project-map]
; Define a local recursive function called "rec" (or whatever)
(letfn [(rec [i project-dates]
(if (= i (count project-map))
project-dates
(.then (.getItem localforage (nth project-map i))
(fn [promiseVal]
(rec
(inc i)
(conj project-dates {(key (nth project-map i)) promiseVale}))))))]
; Then start the recursion off
(rec 0 {})))
The second has the benefit of not needing to pass project-map
constantly, as well as a more succinct function name.
Of course, you need to be cautious if you may have an excessive amount of recursive calls. You'll need to test to see if a lack of recur
is safe.