top | item 9519683

Syncify.js – Eliminates the need for callbacks in the browser

67 points| dgellow | 10 years ago |github.com

35 comments

order
[+] drostie|10 years ago|reply
There's something that I'm missing here. Can anyone who is involved with this project clarify this example:

    function getFullName( id ){
        return ajax( "/user/" + id + "/name" ) + " " + ajax( "/user/" + id + "/lastname" )
    }
I've read through the source and it mentions blocking etc. but I didn't see quite what I was looking for.

So here's the deal: at one point I was working on laziness library to treat promises as lazy values, and the problem that I ran into was that JS doesn't let you overload the operators `+`, `-`, etc. so that the API needs to export things like `Lazy.plus(p1, p2, p3)`. By itself that's not so bad -- it even makes everything look lispy in a strangely C syntax -- but it was sufficiently heavy that I kind of abandoned the project.

So from my understanding, the `+` can only work if the `ajax()` calls now block the global browser JS thread. Is that true? Does the above function even work synchronously, if I call it?

Of course, to actually use this function we have to use `Syncify.revert` which converts it back into a callback-based function. Does Syncify.revert have to somehow parse the function? How does it "stick its own context" into the function that it's calling without something complicated like dynamic variable scope? Or did you find a way to hack dynamic scope into JS?

[+] adrusi|10 years ago|reply
I've only briefly looked through the source, so I'm not sure if they're doing this, but you can sort of intercept operators like `+` by implementing valueOf() on the object. When you perform a primitive operation on an object, the VM calls valueOf() on it to get a primitive value that it can handle. It does not tell you what operation caused valueOf to be called, nor does it let you influence the result (except by the primitive value you choose to return).

I suspect that they're doing something else, and given the Syncify.parallel construct, I don't think they're blocking the whole thread.

[+] adrusi|10 years ago|reply
It seems incredibly fragile, better to just use some kind of compile-to-js language. IcedCoffeeScript, Clojurescript, Gopherscript and more all make it possible to avoid callbacks in a cleaner way, with fewer restrictions and probably better performance. Babel has experimental support for es7 async functions, if you really want to write javascript code.
[+] NDizzle|10 years ago|reply
Excuse my ignorance, but are patterns like the one mentioned in the example in wide use? Chaining together the results of multiple AJAX calls to form a single response? (response might not be the correct term - a single return value)

Wouldn't you just send a request to the server and have it handle things and spit out the correct response/return value? What's the need for multiple ajax calls?! I know we're obviously not using this to fetch first and last names - what's a realistic example for this usage pattern?

[+] alttab|10 years ago|reply
For real, this sounds like it simply allows front-end dev's to scour backend APIs and lace together really slow, really brittle web pages.
[+] dmak|10 years ago|reply
Very common. RESTful architectures always give rise to this type of pattern. For example, you fetch a user id, and then you fetch all the blog posts by the user then you fetch the comments for the blog posts.
[+] Nemcue|10 years ago|reply
Why not use a Promise library instead?
[+] dmak|10 years ago|reply
The idea is to improve code composition by creating synchronicity. With Promises, you generally have to return the promise and then attach a then method to do something which is contagious and creates tons of dependencies on promises.
[+] mbrock|10 years ago|reply
When I see a website for a tricky language thing like this, within five seconds I'm wondering "okay, what EXACTLY does the thing do?"

Sometimes the website answers that. This one doesn't, and so I'm absolutely not going to use it, because I don't understand it.

[+] amelius|10 years ago|reply
My guess: the system keeps calling your function, and throws an exception whenever an asynchronous call needs to be made which was not yet handled. This exception is then caught inside the system to mark the asynchronous call as being done, and the next iteration starts.
[+] dmak|10 years ago|reply
I get that it returns a wrapper, but the functions like map and toUpperCase would have to wait for the asynchronous callback somehow. How does this work?
[+] igl|10 years ago|reply
It basicly a wrapper around Promises.

Nothing of your sync functions work until after you do syncify.revert which gives you a function taking a CALLBACK.

[+] EvanYou|10 years ago|reply
This is quite an interesting hack, and I enjoy seeing novel solutions to the async problem (especially on the browser side, where ES6 is not universally available yet). But still, I would probably never use this in production, given that I can just transpile ES7 async/await with babel.