English | Русский
The «Service Locator» implementation for JavaScript.
npm install @e22m4u/js-service
The module supports ESM and CommonJS standards.
ESM
import {Service} from '@e22m4u/js-service';
CommonJS
const {Service} = require('@e22m4u/js-service');
The module offers ServiceContainer and
Service classes, which can be used separately or
together.
ServiceContainer - classic version of the service
locatorService - hides the creation of the container and its
distributionThe Service class is convenient when the application has
a single entry point created by the new operator. For
example, if such a point is the Application class, we could
inherit it from the Service class and access other services
using the getService method without worrying about creating
and storing their instances.
Moreover, if other services also inherit from the
Service class, they can refer to each other using the
getService method, as if we were passing the service
container between them.
ServiceContainer classMethods:
get(ctor, ...args) returns an existing or new
instancehas(ctor) checks if a constructor exists in the
containeradd(ctor, ...args) adds a constructor to the
containeruse(ctor, ...args) adds a constructor and creates its
instanceset(ctor, service) adds a constructor and its
instanceThe get method of the ServiceContainer
class creates an instance of the given constructor and saves it for next
access following the "singleton" principle.
Example:
import {ServiceContainer} from '@e22m4u/js-service';
// create a new container
const container = new ServiceContainer();
// pass a constructor to the "get" method
// (the Date class is used as an example)
const myDate1 = container.get(Date); // creates an instance
const myDate2 = container.get(Date); // returns existing instance
console.log(myDate1); // Tue Sep 12 2023 19:50:16
console.log(myDate2); // Tue Sep 12 2023 19:50:16
console.log(myDate1 === myDate2); // true
The get method can accept constructor arguments. If the
container already has an instance of this constructor, it will be
recreated with new arguments.
Example:
const myDate1 = container.get(Date, '2025-01-01'); // creates an instance
const myDate2 = container.get(Date); // returns existing instance
const myDate3 = container.get(Date, '2025-05-05'); // recreates
console.log(myDate1); // Wed Jan 01 2025 03:00:00
console.log(myDate2); // Wed Jan 01 2025 03:00:00
console.log(myDate3); // Sun May 05 2030 03:00:00
The ServiceContainer constructor takes a parent
container as its first parameter, which is used as an alternative if the
constructor of the requested instance (service) is not registered in the
current one.
class MyService {}
// create the ServiceContainer instance
// and register a new service (MyService)
const parentContainer = new ServiceContainer();
parentContainer.add(MyService);
// provide the previous container as a parent
// for a new one, and check the service existence
// in a child container
const childContainer = new ServiceContainer(parentContainer);
const hasService = childContainer.has(MyService);
console.log(hasService); // true
Service classMethods:
getService(ctor, ...args) returns an existing or new
instancehasService(ctor) checks if a constructor exists in the
containeraddService(ctor, ...args) adds a constructor to the
containeruseService(ctor, ...args) adds a constructor and
creates its instancesetService(ctor, service) adds a constructor and its
instanceA service is just a class instance. However, if a service inherits
the Service class, such a service encapsulating the
creation of the service container, its storage, and transfer to other
services.
Example:
import {Service} from '@e22m4u/js-service';
// the Foo service
class Foo extends Service {
method() {
// access to the Bar
const bar = this.getService(Bar);
// ...
}
}
// the Bar service
class Bar extends Service {
method() {
// access to the Foo
const foo = this.getService(Foo);
// ...
}
}
// the App service (entry point)
class App extends Service {
method() {
// access to Foo and Bar services
const foo = this.getService(Foo);
const bar = this.getService(Bar);
// ...
}
}
const app = new App();
In the example above, we didn't worry about creating a service
container and passing it between services, because this logic is
encapsulated in the Service class and its
getService method.
The getService method ensures the existence of a single
instance of the requested service, rather than creating a new one each
time. However, when passing additional arguments, the service will be
recreated with these arguments passed to the constructor.
Example:
const foo1 = this.getService(Foo, 'arg'); // creates an instance
const foo2 = this.getService(Foo); // returns existing instance
console.log(foo1 === foo2); // true
const foo3 = this.getService(Foo, 'arg'); // recreates instance
const foo4 = this.getService(Foo); // returns recreated instance
console.log(foo3 === foo4); // true
npm run test
MIT