Transient Services
Normally, when you create a service, it's cached and any further calls to Container.get
(or when the service is used as a dependency) result in the same instance of the service.
In some cases, that behaviour may actually be undesirable. For this use-case, TypeDI provides transient services, which are re-instantiated every time they're requested.
If your service performs complicated calculations, or emits side-effects (e.g. database connections), you may find that the performance of your application quickly deteriorates.
To fix this, you can "hoist" the logic outside of your transient service. Read more about this in the Performance section.
Demo
To demonstrate how transient services, let's create a simple example: a performance timing API. The timing API should correspond with one set of marks alongside a final measurement.
import { Service } from '@freshgum/typedi';
@Service({ transient: true }, [ ])
export class TimerService {
private name: string | null = null;
start (name: string) {
this.name = name;
performance.mark(`${name}-start`);
}
end () {
const endName = `${this.name}-end`;
performance.mark(endName);
performance.measure(this.name, `${this.name}-start`, endName);
}
}
Now, we'll make use of this timing API in our page service, a fictional service which is responsible for rendering pages.
import { Service, HostContainer } from '@freshgum/typedi';
import { TransientRef } from '@freshgum/typedi/contrib/transient-ref';
import { TimerService } from './timer.service';
@Service([
TransientRef(TimerService)
])
export class PageService {
constructor (private timerServiceRef: TransientRef<TimerService>) { }
async renderPage () {
const timer = this.timerServiceRef.create();
timer.start('page-render');
// Perform page rendering logic...
timer.end();
}
}
Now, when a page is rendered, we'll have new performance entries to upload to a central diagnostics server.
Transient Services as Dependencies
When you use a transient service as a dependency, the same instance of the service will
be used over the lifetime over the consuming service. If this isn't the desired behaviour,
you would be better served by the HostContainer()
API, which allows you to get an instance
of the container the service is running under.
Then, you can replace references to the transient service with calls to Container.get
.
In the example above, we did just that. This allowed us to get a new instance of TimerService
for each page that was rendered in the app.
Performance
If your transient service relies on a great number of other transient services, computes expensive computations, or creates side-effects which may affect the application, you may find that transient services affect your application's performance.
For this reason, it's typically recommended to use static services or singletons if your workflow doesn't explicitly require services to be transient.
If you would still prefer transient scenarios in this case, consider hoisting calculations and side-effects out of individual transient services, replacing them with references to a static / singleton service.
TransientRef
In v0.5.0, a new function was added to make the management of transient services easier.
This should replace any prior usages of HostContainer
.