tag:blogger.com,1999:blog-9210025386133363283.post3384015124677721884..comments2023-12-18T02:17:56.198-08:00Comments on Modern JavaScript: Dependency Injection in Closure - IoC with Loaderrhysbrettbowenhttp://www.blogger.com/profile/05642824819846878549noreply@blogger.comBlogger7125tag:blogger.com,1999:blog-9210025386133363283.post-10611723779558399882012-10-11T01:51:55.409-07:002012-10-11T01:51:55.409-07:00That's pretty interesting. I wrote a similar l...That's pretty interesting. I wrote a <a href="http://royjacobs.github.com/intravenous/" rel="nofollow">similar library</a> a while ago, maybe we can share some concepts.Roy Jacobshttp://www.royjacobs.orgnoreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-15066126853312108252012-10-09T23:15:50.755-07:002012-10-09T23:15:50.755-07:00actually coming to think of it, it might be cool t...actually coming to think of it, it might be cool to have Loader as a constructor so you could have separate instances which can put in separate requirements for the same string and then your object's dependencies that are passed in would depend on which instance you called to create the object. I know angular allows you to override some of the dependencies when creating a class, but this would mean that the dependency is somewhere in your code rather than defined right on the class where it is easy to find. I think having Ldr1, Ldr2 etc might be a better solution as it would be easier to trace where the dependencies come fromrhysbrettbowenhttps://www.blogger.com/profile/05642824819846878549noreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-73383929742111224602012-10-09T23:10:32.910-07:002012-10-09T23:10:32.910-07:00circular dependencies cause much less headache usi...circular dependencies cause much less headache using the instSoon method above. If the dependency is actually used in the classes methods instead of the constructor and you had to put dependencies at the top of the file it would be a problem, but allowing the method to instantiate when it's dependencies resolve themselves is pretty powerful - at least when I was testing it with my work's codebase (there is a bit of criss-crossing dependencies in there). Having all the dependencies brought in a single file takes away circular dependencies through goog.require completely, then the instSoon gives the dependencies a chance to resolve themselves in a way that goog.provide just doesn't allow.<br /><br />the extra parameters I'm talking about are those outside of their dependencies, and only if that class is to de a dependency itself, rather than instantiated. Chances are if you want to pass something in when it's being automatically depended upon then that instance of the class should be made as a singleton and passed in rather than letting a new instance of it be passed in.<br /><br />The short name is to make it easy to use - I know polluting the global namespace is an antipattern, but it's one that was made for sites that have third party javascript on and which is not really controlled by the webpage. Chances are if you're using Closure Tools you're writing a large application and are in control of the global namespace - and if you're not it's easy enough to take the file and just do a replaceAll to put the namespace you need on it. All the modules I write are meant to be incorporated and compiled in to an application rather than be used separately, though I'm sure it's not too hard to change things.<br /><br />In this case I think the decoration is okay, as if you take away Loader you can still use the class normally and inject the dependencies manually. Perhaps there should be an option to inject the dependencies when you instantiate and object, or some sort of registry - but then you would have to keep a registry of all the objects that could be instantiated. Keeping an array of strings keeps things decoupled and gives a hint to whatever IoC you go with a hint about what should be loaded. The actual angular approach (and one taken by others) is to parse the function to get a hint from the variables you pass in - but that's not possible with compilation. An array of strings seems to be the lesser of evils while making it easier to maintain a project. At some point you have to buy in to a certain way of coding to work well with whatever library you're using.<br /><br />Have you got any ideas about matching up the Class with it's dependencies? I was going to try an array that pointed to a cache so it would compile down but then the class would break without Loader so I went back to an array of strings. I thought about passing in strings, but then the class that is instantiating it needs to know what sort of dependencies to pass in and they would have to be declared every time you instantiated a class. It would make it easier to make more abstract classes because you could pass in different hints to Loader and so you'd come back with classes that have different implementations of dependencies - which would be cool but tricky to keep track of.<br /><br />But this is all just from me playing around and putting in a solution at work that seems to work for me. I'm hoping that putting it out there will get more people thinking about it.rhysbrettbowenhttps://www.blogger.com/profile/05642824819846878549noreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-46218235036782536472012-10-09T13:15:41.661-07:002012-10-09T13:15:41.661-07:00Quick notes:
Circular dependencies is always a pro...Quick notes:<br />Circular dependencies is always a problem, no matter if modules are loaded in compile time or run time.<br /><br />I really don't like idea of passing classes instead of instances. If we need instance, put them a instance. Don't sacrifice clean design for sake of IoC container.<br /><br />"require('Ldr');"<br />Please prefix your code with some namespace. It's not a kind to mess a global scope.<br /><br />"classes really shouldn't have any extra parameters? "<br />Classes should have exactly these parameters which they needs to declare their dependencies. <br /><br />myClass.prototype.inject_ is so Angulary. I don't like the way we have to decorate our classes to work with IoC container.<br /><br />Anyway, I like the DI movement in Closure world.Daniel Steigerwaldhttps://www.blogger.com/profile/14925689736283077556noreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-79937722478509944442012-10-08T23:49:28.141-07:002012-10-08T23:49:28.141-07:00I meant:
ldr.instSingle('mediator' mvc.Me...I meant:<br /><br />ldr.instSingle('mediator' mvc.Mediator)rhysbrettbowenhttps://www.blogger.com/profile/05642824819846878549noreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-32678430291151729662012-10-08T23:48:09.315-07:002012-10-08T23:48:09.315-07:00the reason they're put on the prototype is so ...the reason they're put on the prototype is so that it works with Advanced Optimizations. I wanted to have them as a Class variable but then the compiler changes the namespace so it's not the easiest to get.<br /><br />Putting in the names of the dependencies allows Loader to locate the dependencies for you, rather than having to pass them in manually. I only mentioned Plastron as a case for when you might need to pass it a constructor function that you want to have dependencies resolved for.<br /><br />Basically the Loader will act as your factory for creating instances and resolve dependencies for you based on what you give it. For instance if I have a mediator and I want it available throughout the program then in my main file I just need to put:<br /><br />Ldr.instSingle(mvc.Mediator);<br /><br />then in any class I use throughout the program I can easily give it to the class like this:<br /><br />myClass = function(mediator) {}<br /><br />myClass.prototype.inject_ = ['mediator']<br /><br />now whenever I instantiate the class it will automatically pass in the mediator for me:<br /><br />var myInst = Ldr.inst(myClass);<br /><br />you'll start to see how this is useful when you start having several dependencies that are needed by several classes, and dependencies that have dependencies and so forth because you just declare the dependencies on the class and when you instantiate it then it will go through and load the rest of the dependencies for you rather than you having to manually pass them all in.rhysbrettbowenhttps://www.blogger.com/profile/05642824819846878549noreply@blogger.comtag:blogger.com,1999:blog-9210025386133363283.post-28355666340770730832012-10-08T23:39:02.426-07:002012-10-08T23:39:02.426-07:00I don't really understand the benefit from mov...I don't really understand the benefit from moving declarations from the top of the file in a prototype property, except in the rare cases of circular dependencies. In those (rare) cases the technique described initially is doing well enough.<br /><br />I can easily imagine it was written specifically for Plastron, because from trying it I still have the bad taste in my mouth, having to juggle with constructor/classes back and forth.<br /><br />I don't think it is generally applicable, but thanks for the effort.PeterStJhttps://www.blogger.com/profile/04425523630769302410noreply@blogger.com