Right away I thought that lack of variables would be a big problem, but as it turned out, that wasn't the case at all.
After analyzing my JavaScript code, I realized that, in fact, we used mutable operations not so often. Instead of it, usually, we save intermediate results in
const variables and use them in other functions. However, in some cases, we use
let variables in JS (which are mutated in the cases of calculations in loops) but they also can be replaced by
reduce or recursion.
Speaking of frontend,
data persisting requires using state management tools that are quite similar to
Clojure's Atoms or Re-frame events.
Finally, asynchrony. After first reading about asynchrony,
сoncurrency, and parallelism in Clojure, it seemed to be very difficult. But some time later, after better understanding, everything fell into place.
I also noticed that most cases (at least, what came across to me) cover Clojure
core.async channels usage.