-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document difference from GopherJS #56
Comments
Thanks for opening this issue @FlorianUekermann. Definitely need to document this better. Will answer each of them better but for now, I'll copying and pasting what I wrote before here: GopherJS is an awesome project and I gave it an honest go before working on Joy. It seemed like GopherJS approached the compiler wanting to compile existing Go code to Javascript code. Getting big Go programs working in the browser is a huge accomplishment, but it's not the approach I took with Joy. My approach to Joy was asking myself: Could I create a more productive frontend development environment in Go than by just using Typescript, Webpack, React and the Javascript module ecosystem? I believe the answer to that will soon be yes. This question led me to an entirely different architecture that just didn't seem feasible to do in GopherJS without basically rewriting it. Now, it's hard to say: If I had spent all this time just refactoring GopherJS, could it be the same project? The answer is maybe – I'm not really sure. |
Does that mean Joy will not try very hard to be compatible with existing go code (maybe relaxed stdlib compatibility)? Or is compiling existing code one of multiple goals.
Could you elaborate a bit on that. Maybe an example of an architectural difference? I saw that you put a lot of effort into efficient dom integration, which has a couple of rough edges in GopherJS. I assume this has some implications for how go interacts with JS variables. Is that something you found difficult to realize in GopherJS? |
Another important difference today is that GopherJS implements much more of Go's standard library and the syntax translation is more complete. This will get filled in as we reach 1.0 and 2.0, but most existing Go programs that use the standard library won't yet compile. I'm hoping to get your help to make this happen faster! Some links:
|
My takeaway from what you're saying is: "GopherJS started with Go as a priority and is working towards great JavaScript interoperability whereas Joy started with JavaScript as a priority and is working towards great Go interoperability." Is that roughly correct? Regardless, this type of project seems like a lot of fun regardless of whether it is used alongside or instead of GopherJS. |
@PaluMacil exactly right! That's a really nice way of putting it. |
Added a section on the website: https://mat.tm/joy#faq-gopherjs Thanks @PaluMacil for that wonderful summary. |
@matthewmueller - just taking a look through the website etc for Joy - a very impressive release. I've contributed a bit to the GopherJS project so am particularly interested in the comparison between the two. The line in the summary above that caught my eye way:
To my mind the JavaScript interoperability of GopherJS is very well defined and implemented (notwithstanding this open issue where there are certain bits that need tidying up). What particularly did you find lacking? |
@myitcv Hey dude! I saw you on quite a few issues for GopherJS, so I'm happy you've stopped by. Let me try and get more specific and maybe you have some thoughts and solutions to these issues. This is more tailored to what I found lacking about Gopher, but there's a bunch of stuff that's missing from Joy that Gopher handles beautifully.
My gut feeling for how this plays out is that Gopher will be a lot more compatible with existing Go code. Things like great pointer support, a more proper goroutine model etc. Joy probably won't go this way and will probably opt for compiler errors when it comes across those types of things (e.g. a My aim for Joy is to be a great alternative to Typescript/Flow and my hope is that I can bring a bunch of JS devs to Go as they look for ways to build more stable web applications. |
I can only talk about my reasons for being interested in joy.
So in a nutshell if i was to program a huge web-app i would probably go the go/webassembly way. |
The reason is simple. You can't use or emulate async/await in event listeners and other non-async js calls. That means you won't be able to use channels or locks there without some kind of scheduler. That is particularly useful inside event listeners. The scheduler in gopherJS isn't even that complex, it just keeps lists of which go routine is waiting on which channel and executes it as soon as you do a send. Sooner or later you'll need this. Fortunately it's not that complex, now that gopherjs spelled out how to do it.
This. So much. It's both a size issue as well as a performance problem.
+1 |
@FlorianUekermann thanks for the details and the link, the example you provided in that issue is a good test to try out.
Hmm, sorry I'm not quite following this. Why doesn't this work? var btn = document.getElementByID("btn")
btn.addEventListener('click', async function() {
document.write('oh hai')
}) Alternatively, maybe this? var btn = document.getElementByID("btn")
btn.addEventListener('click', function() {
(async () => {
document.write('oh hai')
})()
}) |
You didn't put await in there. Using async functions is always possible (but rarely sensible in an event listener, since your code won't be executed in order anymore). If you just put Same is true for using await in any other synchronous context. So you can't use async & await to implement channels, if you want to be able to call go code from JS (including event listeners). I don't see a way around writing a simple scheduler until these design issues are fixed in JS (seems unlikely). |
Okay bear with me as I try to understand this problem better. I've read through the Gopher issue and also some of the outbound links. It sounds like what you're saying is that this won't always work: window.addEventListener("keydown", async (e) => {
var ch = e.key
await sleep(500)
var pre = document.querySelector("pre")
pre.textContent = pre.textContent+ch
})
function sleep(ms) {
return new Promise((res, rej) => {
setTimeout(res, ms)
})
} There's a chance the promises will get executed out of order resulting in your text no longer matching your input. And this is an issue because in this particular case, the order of callbacks matter. Is that the problem you're talking about? |
If you use a random sleep time or a fetch instead of the sleep you'll probably see the characters out of order if you type fast enough. Not entirely sure in your particular example, since I'm not an expert on scheduling in JS. But I don't think discussing the finer details of how the JS scheduler works is necessary for the discussion of a Go implementation. The problem is simple: If you use a normal event listener or JS call without async, you won't be able to use await, so you can't implement a channel receive by using await, nor any of the other synchronization primitives Go provides. If you are wondering why someone may want to use non-async event listeners in the first place, consider that JS has a well defined event flow (https://www.w3.org/TR/DOM-Level-3-Events/#event-flow), which gives you a lot of useful guarantees to work with (serial execution of event listeners, ordering of event listeners, bubbling, cancellation, etc.). All of that goes out the window once you start using async.
I personally like option 3 the best, but you may have different goals than I do. |
Got it – thanks for clarifying and I'll make sure to test for this. The implementation is not set in stone by any means and it sounds like I'm mistaken about what the GopherJS scheduler is actually doing. We may very well end up going the GopherJS route here. You probably saved me some time and headache so cheers for that 🍻 |
What about wrapping over DOM events with something like an event delegation setup.
It'll add a bit more runtime, but it will support most use-cases without doing the fancy stack tracking that GopherJS has. Since Go already uses goroutines in a lot of places, it's already equipped to handle coordinating async actions, so I don't think it'll be all that hard for somebody to listen on different events and coordinate between them with channels. Your code will look more like regular async-heavy Go in the end |
Something like domdelegate but with support for async functions like promise-events |
Possible and not even very hard. Whether you want to reinvent that part of the platform is a different question. Note that you will still have to trade in certain properties. For example, browsers freeze the interface until event listeners are done executing. |
What about preventing the use of channels inside eventListeners by default (like you proposed), but providing this async API in case you do want to use channels inside eventListeners. |
First off, I'm very happy to see someone having another go at this. I'm very impressed by what I've seen.
That said, most people will ask themselves how this project differs from GopherJS.
I've been using GopherJS for a while in production now and don't feel like it is missing anything fundamental.
Could you clarify...
The answers probably belong into the readme and FAQ, since this is probably every new visitors first question.
The text was updated successfully, but these errors were encountered: