Fork me on GitHub
#clojurescript
<
2022-05-08
>
Nundrum03:05:46

Where can I go to get an explanation of how to fetch data using Clojurescript in a browser? All the examples I can find just stuff the result to the console.

didibus05:05:41

What do you mean by "fetch" data?

Nundrum14:05:11

Right. I can fetch it, but I all the fetching examples just end up calling console.log(). I don't understand how to get anything useful done with the data. Like using cljs-http I can (go (<! (http-get))) but that gives me a channel. There's something about the basic model of working the browser that I don't understand and can't figure out.

Alexis Schad15:05:39

What's wrong with "just end up calling console.log()"? What do you want to do with the result? Can't you just replace console.log with your code?

Alexis Schad15:05:07

I guess you wouldn't know how to do it in JS neither, because you want a synchronous way to fetch, don't you?

Nundrum19:05:22

It's a mental model fit problem. 99% of all the Clojure code works like: "I need THIS to be a result of FROBBING on THAT" and the code mostly just falls out of my head and onto the screen. That's the magic that makes Clojure to nice to me. That model is not working with Clojurescript and I can't figure out the new model. I tried putting a block to replace a div in the go block, but that fails. I get that I can't have synchronous code, but have failed to grok something that's fundamental, I guess. Something about where/when code is running is eluding me. So now I'm working through: http://funcool.github.io/clojurescript-unraveled/

Alexis Schad19:05:21

I think you have missed the important concept of concurrency, the langage was created to manage concurrent programming (that's one reason why all is immutable). For a simple solution, you just have to "wrap" your code around a go block to make it async. Inside it you can just use async result with almost a sync syntax (<! or <p! depending if it's a channel or promise). It's the same way you would use async/await in JS (that's why I was asking if you know how to do in JS).

Alexis Schad19:05:45

https://clojurescript.org/guides/promise-interop#using-promises-with-core-async you have a small snippet here. I don't recommand using the above snippets with using promises directly (that's not really the clojure way for me)

Nundrum19:05:49

I don't know how to do it in JS. I am missing that foundation. Clojure concurrency isn't an issue for me, but the browser is just a completely different platform and I don't grok it. When I try to do things in the go block, it's not working, which is why my confusion.

Nundrum19:05:50

Back to Reading The Fine Manual now ;D

👍 1
Alexis Schad19:05:14

Feel free to ask with a code snippet the things you've tried if after the reading you're still confused

p-himik19:05:27

The simplest paraphrasing of how it works: "Hey, JS, run this code and ping me with the result". That "ping" can be: • A callback - doStuff(onStuffDone) • A promise - doStuff().then(onStuffDone) (`async/await` in JS is almost the same thing) • core.async - (go (let [r (<! (doStuff))] (onStuffDone r)))

1
didibus18:05:22

You should be able to replace the call to console.log with a call to whatever else you want to do with the result.and that should work. So if it doesn't, it's not that you're not correctly getting the result, but what you're doing probably just doesn't work

Nundrum18:05:27

I guess it's the latter. I'm not understanding the context in which the call is happening, or how to control it.

Alexis Schad18:05:56

If you still try to understand, can you give what langage you learnt before Clojure? (especially one that have concurrent/async stuff if so)

Nundrum20:05:33

I've worked in a range of languages from C to Python. Probably the most was in Java.

didibus21:05:23

Ya, you don't control the context. The JS browser runtime will allocate your code inside its own context. So it gets weird, you can refer to this using this-as which is often magically bound to something based on what the callback was for. And you have all these globals from the browser from js/window. And then for some events, to the callback is passed arguments while others it isn't. Those arguments are super loose, your function doesn't have to take any arguments it'll still work, so if you don't care to have them provided you can make a zero-arity, but if you want them you have to make it the right arity.

didibus21:05:25

Basically, when you code for a browser, the browser is like a giant framework. It calls you, you have to play by its rules. You need to hook into it and extend it the way it wants.

didibus21:05:22

And then there's all the security measures as well. You might.wknder.wjy something isn't working or returning nil when it's because the browser blocked the call because you didn't properly configure things for cross-region calls or other such things. It won't error at you and explain itself necessarily.

didibus21:05:02

Also, keep track of what takes a callback or returns a promise, for all those things, you need an additional async handling, if using core.async that be another <p!or <! or you might need to orchestrate the callback to channel conversion yourself, etc. Otherwise you can also just use promise/callbacks directly. Or use some syntax sugar over them like promesa provides.

Nundrum21:05:07

Is there something that explains all of that succinctly? Like the Android dev guide makes it all really clear when/how your app is called. It seems like everyone who understands the environment for the browser is has just learned it through experience.

didibus21:05:45

In my experience, most web devs don't understand it, just trial/error and copy/paste from online answers 😝

didibus21:05:39

The other challenge is you don't have only one browser, you have many, so you're trying to write something that somehow will run when executing within Edge, Chrome, Firefox Safari, mobile/desktop variants. iE, and different versions of them, etc.

didibus21:05:16

But this is the best documentation for it all in my opinion: https://developer.mozilla.org/en-US/

didibus21:05:40

Always remember to look at the compatibility list also before using some API, it'll tell you what browser/version is supported fully/partially or not at all.

didibus21:05:46

Going through the reference would help a lot.

didibus21:05:33

Also to your particular question, I suggest reading about the event loop, that's the dispatch model: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop

gratitude 1
Alexis Schad22:05:43

You can try understanding the simplest example of asynchronous code in a GUI : the button. When you have a button in your browser, you subscribe to the 'click' event and give a function. That function is called when the button is clicked. That's all you need to know. When programming, you don't wait synchronously in the main thread for the button to be clicked, else you won't be able to have others buttons or do other things. So you tell the browser to call this function back when it's clicked. That's the same with fetch: you tell the browser to fetch and later to call a function when it's done.

Nundrum19:05:49

That event loop article was helpful. It brought what I already knew about GUI programming in line with the browser context. And then I quickly realized my HTML wasn't getting fully rendered before the async call was running.

👍 2
Alexis Schad20:05:17

Do you use any library for manipulating/creating the HTML? Because this kind of problems is common and easily fixable (maybe you have fixed it already)

Nundrum20:05:41

I fixed it already. Thus far I'm just using Reagent.

Alexis Schad09:05:59

Hi, maybe you could give a try to https://funcool.github.io/promesa/latest/user-guide.html That's a lot more easier for doing async in the browser