infuse.js ioc javascript library

| 4 min read

Infuse.js is an IOC javascript library (inversion of control).

Using rules based on properties and paramaters naming, you will be able to inject data in functions or objects.

Quick video for the impatient.

Why would I need to inject anything anywhere?

Dependency injection is used in many languages, the concept is that some data are injected automatically when you create a "class" or other re-usable component.

Just a few advantages of using injection not to name them all. Injection will reduce boilerplate code (increasing readability), dependencies between components and you will be able to produce a much more re-usable code. Injection is also very good to produce a highly-testable code.

The application you are building will also benefit from lazy instantiation, which is very good, the instances will be created only when they are used and when you need them.

Infuse.js is a pretty small library compared to the huge benefit you can gain.

So... How does this work?

In short, you are going to create some rules based on names (string), you will provide data to inject (string, number, array, boolean, objects, function, and probably anything that can be hold in a variable).

When these rules are created, you are going to use their names as properties or constructor parameters. And the injector will take care of populating these variables with the right content, no strings attached!

Sorry I still don't get it...

Let's take an example then, you are building a huge app with several developers, javascript files, components, and so on. You have a basic function called "Settings" that will hold a lot of information and you like to use it in about anything in the app. How do you do that?

Well, you could create some kind of global object, you can access it everywhere and it is done!

window.Settings = { deploy: 'dev', domain: 'localhost' }

But in that case you will create a direct dependency on a object (Settings), which is bad for tons of reasons. Hard to test, not re-usable because of the dependencies, and so on. You should always stick to the Law of Demeter.

Another solution would be to create that object and pass it in everything you need, that would be a better a solution, but still very hard to maintain and not ideal.

With injection you can do the same thing in a much easier way (which is populating variable with something external), especially if you want to inject tons of things. But this could also be automatically done!

It would be nice to just say: "ok I've created these 6 components, I really would like to have that "settings" variable automatically set without doing anything or adding code for it!". Well that's what infuse.js will do.

Sounds good! Let's see some code!

Well first, create an injector instance.

create injector var injector = new infuse.Injector();

Now you create an object you want to access to from everywhere, just as an example, it could be a function, an array, a string, or whatever.

create object var settings = { deploy: 'dev', domain: 'localhost' }

Now you want to say: "ok, every time something contains the variable 'settings', or has a constructor parameter 'settings', I want that object to be set in."

That is nothing more than a mapping rule. Here is an example.

injector.mapValue('settings', settings);

Last step is populating the variables. This can be done in two ways: manually or automatically. Here is how to do that manually:

// a function
var Receiver = function() {
this.settings = null;
// create an instance
var receiver = new Receiver();
// populate the settings variable

That's basically it, you can add a postConstruct method, which will be automatically called when the injection is done.

Receiver.prototype.postConstruct = function() { alert(this.settings); // got it! }

Easy? Let's see the automatic version where the injector will take care of instantiating the function and populating the variables.

// a function
var Receiver = function() {
this.settings = null;
Receiver.prototype.postConstruct = function() {
alert(this.settings); // got it!
// create an instance
var receiver = injector.createInstance(Receiver);

Works also with a constructor.

// a function
var Receiver = function() {
this.settings = null;
Receiver.prototype.postConstruct = function() {
alert(this.settings); // got it!
// create an instance
var receiver = injector.createInstance(Receiver);

The injector can inject data in several ways, and can also take care of instantiation, of what should be injected and how it should injected. If we turn the data to a function:

var Settings = function() {
this.deploy = 'dev';
this.domain = 'localhost';

We can use another type of rule (mapClass):

injector.mapClass('settings', Settings);

The injector will now inject a new instance of Settings every time it has to be injected somewhere (like doing a new Settings() and sending it).

This might not be ideal, maybe you want to inject the same instance all the time so you have some kind of shared unique instance? This is called a "Singleton mapping". Don't be scared by the name if you don't like Singleton, they are not really Singleton. It just means that they are created only once and the same instance will be injected everywhere. You can do that by changing the rules like this:

injector.mapValue('settings', settings, true);

As the "settings" rule has been set "as Singleton", the same settings instance will be injected in both functions.

var FooClass1 = function() {
this.settings = null;
var FooClass2 = function() {
this.settings = null;
var foo1 = injector.createInstance(FooClass1);
var foo2 = injector.createInstance(FooClass2);
// next line will alert true because the settings injected
// will be the same instance (mapped as Singleton)
alert(foo1.settings === foo2.settings);

This is just a small overview, you can do tons of things with injection and infuse.js.

Where do I get more info?

The repo is there, where you can find more examples (you can also check the tests in the repo to get a complete overview):

Install with npm (infuse.js works with node.js):

npm install infuse.js
var Injector = require("infuse.js").Injector;
var injector = new Injector();
injector.mapValue('name', 'John');
var Person = function(name) { this.nameParam = name; };
var john = injector.createInstance(Person);

And the demo from the video.