6 ms·
Faster, Better DOM manipulation with Dommy and ClojureScript
- aria 13y agoAuthor here. Happy to answer any questions/concerns.
- zackzackzack 13y agoDid the speedup of script execution have other costs? One would imagine that using Clojurescript would incur some other costs somewhere. This feels like a free lunch somehow.
- aria 13y agoClojureScript generates a little more ephemeral garbage than native JavaScript and the Clojure data structures are slower, but in reality, the bottlenecks tend to be things which cross the DOM barrier and macros can make those bits much more efficiently. So it's not a free lunch, but it's very very cheap and tasty.
- bjourne 13y agoIt's incompatible with standard Javascript libraries, which is why you would use Dommy because you can't use jQuery. The ClojureScript compiler is also fairly slow (due to google closure compiler I think) so even with a running jvm it takes several seconds to compile small example files. To slow for me so I switched back to CoffeScript which is lightning fast.
- rads 13y ago"It's incompatible with standard Javascript libraries, which is why you would use Dommy because you can't use jQuery." Not true. (def $ js/jQuery) (.append ($ "body") "hello world") The reasons you'd use Dommy over jQuery are outlined in the original post.
- bjourne 13y agoNot quite. The following shows what doesn't work: (def $ js/jQuery) (.each ($ "body") (fn [idx, val] (.write js/document "In a lambda"))) The Google Closure Compiler munges names of functions so that any function declared in ClojureScript cannot be called from jQuery which means that no jQuery function that takes a callback can be used. And you really want to use GCC because without its dead code removal a simple helloworld.js file takes more than 700kb.
- swannodette 13y agoYou just need to compile your ClojureScript with the popular jQuery externs file.
- jwhitlark 13y agoYou can mark things so that their names aren't mudged via ^:export.
- dustingetz 13y agodoes Dommy provide a pure API on top of the DOM? (e.g., lens based) I don't immediately understand how one would make that performant given that the DOM is a mutable data structure. edit: WebFUI[1] is one clojurescript project trying to provide a pure interface for dom manipulation; there are others. [1] https://github.com/drcode/webfui https://github.com/drcode/webfui
- aria 13y agoNo. We're not trying to do something pure on top of the DOM. That isn't feasible for performant manipulation. Being functional is about more than just immutability. We use standard manipulation.
- laureny 13y ago> I don't immediately understand how one would make that performant given that the DOM is a mutable data structure. As a general rule, mutable API's tend to outperform immutable ones.
- jzelinskie 13y agoHow mature is ClojureScript these days? I remember people saying it and Clojure on Android was rough when I was exploring Clojure a while back. Does the compiler eliminate unused code from the final output?
- piranha 13y ago> How mature is ClojureScript these days? Seems to be pretty mature, there are apps in App Store written in it, and there are companies, using it for their front-end (i.e. Prismatic :)). > Does the compiler eliminate unused code from the final output? That's done by Google Closure Compiler in advanced mode.
- ConstantineXVI 13y agoI'm led to believe the issues with Clojure (and other JVM languages) on Android are due to Dalvik not being as friendly to other languages as the Sun JVM. I don't blame Google, but it's unfortunate.
- jwhitlark 13y agoThere are actually games written in Clojure that run on Android quite well. A bit slow to start up, but not nearly as bad as I had expected. Take a look at https://play.google.com/store/apps/details?id=com.friendlyvillagers.ballz&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5mcmllbmRseXZpbGxhZ2Vycy5iYWxseiJd https://play.google.com/store/apps/details?id=com.friendlyvi... and check out their development blog. EDIT: The guy who did NightWeb talks about Clojure on Android here: http://nightweb.net/blog/clojure-on-android.html http://nightweb.net/blog/clojure-on-android.html
- mtrimpe 13y agoWould it be possible to (document how to) replace jQuery in Backbone apps with Dommy?
- deleted 13y ago[deleted]
- jlongster 13y agoClojureScript is so different from JavaScript that it makes sense write a more native DOM library for it. As someone with a lisp background, it's very cool to see a high-profile company like Prismatic using it. However, macros for javascript are being worked on. sweet.js is coming along really well, and just needs to continue ironing out bugs and maturing. http://sweetjs.org/ http://sweetjs.org/ I believe that it could have a profound effect on JavaScript, such as parsing selector string at expand time.
- aria 13y agoOther languages can totally have macros, but unless you have homoiconicity, which lisp languages do, macros aren't easy to use or support. In ClojureScript, macros are built into the language.
- jlongster 13y agoThat really only applies to `define-macro` style macros. You can have syntax-case style macros if the language can disambiguate reading and parsing, which a lot of them have trouble with, and why they don't support them. sweet.js figured out how to do that in javascript, so we have full syntax-case macros just as easily.
- swannodette 13y agoWait so does sweet.js support arbitrary JS execution in macros now?
- jlongster 13y agoNot yet, but it's theoretically possibly with all the groundwork that's already been done. See https://github.com/mozilla/sweet.js/issues/12 https://github.com/mozilla/sweet.js/issues/12 So I should have said syntax-rules (for now). My bad!
- swannodette 13y ago
- st3redstripe 13y agoWhilst I'm sure this is clever - I guess I'll never understand the obsession with micro DOM optimisations. When, ever, are we severely held back by the 'speed' of our selectors? It just doesn't happen!
- epidemian 13y agoThere are some web apps out there that are sluggish as hell if one doesn't have the latest beefy machine. Gmail or Google Doc running on old hardwere are examples of this. "Mobile web" apps are very sensitive to DOM manipulation performance too. I'm not saying that all sluggish performance in web apps is caused by inefficient DOM manipulations, but having a DRY and efficient way to express DOM manipulations could help a lot in that regard =D
- aria 13y agoOn mobile devices, we were hitting significant performance barriers from DOM and class manipulation. YMMV but it seems DOM performance is an issue on non-beefy boxes.
- olenhad 13y agoThis is super impressive. I'm going to use this for my frontend work now. On a side note, what's the idiomatic structure, or "design pattern" for cljs front end code? I would assume something based on MVC, with models comprising of atoms with watches, Views consisting of hiccup templates and controllers gluing dom events to models and views. Am I close?
- aria 13y agoWe internally have a nice component/widget abstraction we use which is not quite MVC, but we think cleans up a lot of web development. We will release in the near future once we perfect it.
- Jonovono 13y agoCool! I am wondering if you have worked with other frameworks like Pedestal.io, C2, or WebFUI, Ganelon. Or any others. What do you think of them? I am just getting started with Clojure/CS and am evaluating the different options. http://pedestal.io/ http://pedestal.io/ http://keminglabs.com/c2/ http://keminglabs.com/c2/ https://github.com/drcode/webfui https://github.com/drcode/webfui http://ganelon.tomeklipski.com/ http://ganelon.tomeklipski.com/
- codewright 13y agoTake a look at Luminus.
- codewright 13y agoAre you going to re-release the stuff you yanked off your github?
- connerp 13y agoI'm not sure there's an agreed upon design pattern. At Prismatic we've adopted a component-based system where a component is essentially the MVC for a single logically-grouped part of the application. Its defined as a record that binds its own events and renders markup from it's template. We try to push mutability and asynchronous functions (xhr, file io, etc.) as far up as possible to avoid unnecessary state manipulation and callbacks everywhere. The idea of reactive programming in ClojureScript is also very interesting as it would make event-handling much more manageable, simplifying event-dom glue code and removing unwieldy callback chains.
- k3n 13y agoInteresting, but I'm not sure how appropriate it is to be comparing it to jQuery in such a head-to-head fashion such as by saying "15x slower", etc. Does Dommy offer the same features (including the browser support) that jQuery does? If not, then you're just comparing apples to oranges, and it doesn't sound like it does (or even plans to) on account that it sounds like there are design decisions that separate the two with regards to the published API ("Inspired by jQuery, but adapted to be functional in order to better fit with ClojureScript core"). Also, wouldn't it be more accurate for the selector testing to actually test against Sizzle[1]? Other features aren't even present in jQuery, such as templating, and so I'm not sure why you'd even compare that. Yes people can and do use templates with jQuery, but that's an implementation detail and is not a concern of the library itself; jQuery does not coerce or force you to use a slow templating system, and most any good templating system will also have a compilation step that is run at build-time. So yeah, you can take some ugly userland jQuery example code and make specific code that is faster.. 1. https://github.com/jquery/sizzle https://github.com/jquery/sizzle
- connerp 13y ago> Does Dommy offer the same features (including the browser support) that jQuery does? No, currently Dommy has a smaller feature set that we think covers a majority of use cases, while maintaining reasonable browser support. Our general philosophy is to add functionality as we need it or others request it. I don't think this makes the comparison invalid. We're comparing the general use cases (selectors, basic dom manipulation, etc.) that any DOM library should have. Can you point out a specific comparison that doesn't apply because of api differences or browser support? > wouldn't it be more accurate for the selector testing to actually test against Sizzle[1]? Part of the point is to show that you can achieve the same elegant chaining-like syntax as jQuery without wrapping selections, so maintaining the wrapped jQuery selectors are important for comparison. > Other features aren't even present in jQuery, such as templating, and so I'm not sure why you'd even compare that. The point of the templating comparison is to show that macros can provide a significant performance boost while maintaining a sane syntax.
- k3n 13y ago
- d0m 13y ago>> Again the time saving comes from macros moving the work of parsing the template data structures from runtime to compile-time and directly generating efficient JavaScript. If it ends being javascript string in the ends, how is it 7x faster (or whatever number)? I mean, sure the compiler could optimize a part of my code, but other javascript compiler could do it to.. right? Although I find the Clojure example very sexy, I don't like how the examples tries to compare to contrived Javascript. I.e. I've been coding javascript for a couple years and I've never used jQuery "sort/filter/slice". But more importantly, it uses pre-defined function in Dommy but not in javascript. For instance: (->> (sel [:ul.my-list :li]) (sort-by #(-> % (sel :input.last-name) .-value)) This uses sort-by where there's: function(a, b) { return ( $(a).find('input.last-name').val() .localeCompare( $(b).find('input.last-name').val() ) ); in Javascript.. Obviously, I can say: $('ul.my-list li').sortBy(function(x) { return x.attr('last-name'); } My point isn't that much that jQuery is longer/shorter, but mostly that if two examples in two different languages are to be compared, it makes sense to use the same function.. where in this case sort-by is a high-level sort. >> One is the loneliest number It's not just "1" or "more than one", it's also zero. Iterating on a list makes it such that you can freely think in a high-level way about the operation and not about the exceptional cases. I.e. $('.blabla').hide(); It Just Works. >> (mapv #(add-class! % :first-ten-adults))) Yes, of course you can use map.. but using $('..').addClass('first-ten-adults') makes it so much easier to deal with, instead of knowing what works on one object, what works on multiple objects, what will throw an error if there's nothing, etc. Meh. I think Dommy is a great library but the author didn't do a great job at explaining why it rocks. I guess attacking a very popular language with its most popular library doesn't help :p
- laughinghan 13y agoRe sort-by: the point there was to show how Dommy gets for free "features" that have to be added to jQuery and contribute to its code size. Re one/map: you can still do operations on sets of 0, 1, or any number of elements, without knowing how many, by always doing map. There's nothing to keep track of, everything always only works on one object, so you're explicit about whether you're operating on exactly one object, or whether you don't care how many objects you're operating on. The latter is just as convenient as jQuery; the former is safer and deliberate. In jQuery, on the other hand, you have to keep track of what works on one object and what works on multiple objects: .text() and .text('a string') are asymmetrical, for example.
- dmix 13y agoI'd love to use Clojure and clojurescript to replace js/ruby. It's a shame I never come across consulting gigs that use it. Or know any local clojure devs, so I'm still wary of using it on my own projects. So it continues to only be the ideal choice for pet projects.
- codewright 13y agoCarthago delenda est: when are you re-releasing the software you yanked from your Github?
- w01fe 13y agoWe're working on it! We removed the software because it needed extensive cross-project reorganization, consolidation, and cleanup which just wasn't possible to do with a clean upgrade path using available resources (3 backend engineers). Plans are to re-release all of this and more, and we've already started with Plumbing and Graph: https://github.com/prismatic/plumbing https://github.com/prismatic/plumbing. Which librar(ies) in particular are you most interested in?
- iamleppert 13y agoIt would be more interesting if someone wrote something like this for standard jQuery-compatible syntax. jQuery code in, compiled selectors out. And it's just standard javascript, so no learning curve to learn or anything.
- staltz 13y agoYes, and a compile step is necessary to produce JS code for those macros. Sounds like it would be really good with coffeescript, like.
- j_m_b 13y agoAll this talk of jQuery and no mention of domina (https://github.com/levand/domina https://github.com/levand/domina) the native clojurescript dom manipulation library? I've since abandoned css and jquery selectors in favor of using domina.xpath. I also want to mention webfui (https://github.com/drcode/webfui https://github.com/drcode/webfui). It is authored by Conrad Barski, who also wrote Land of Lisp. He gave a nice talk about it at the Chicago Clojure meetup group a few months back. He is a fellow hacker news user so I figured he deserved a shout out.