Closed raymondfeng closed 7 years ago
Singleton: the bound service is completely stateless and no request dependency (for example, a utility such as password hashing) is needed. For optimal performance/memory footprint, we'll only create the instance once and reuse it within the same context.
FWIW, this can be already achieved by creating the singleton instance at binding time.
const createDependency = () => { /*...*/ };
// static/singleton
const singleton = createDependency();
ctx.bind('foo').to(singleton);
Transient: the bound service requires a new instance per request.
This is already available AFAICT.
const createDependency = () => { /*...*/ };
// dynamic/per-request
ctx.bind('foo').toDynamicValue(createDependency);
Pooled: the bound service (for example, a repository that has a connection pool to a DB) cannot be shared but it's expensive to instantiate/setup. We can maintain a pool of such instances.
This is an interesting use case. To support it, we need some mechanism allowing dependency consumers to release the resource after the operation has completed. Since the code using @inject
should not be aware of how the dependencies are created (this is by design), I think our only option is to release pooled instances when the request handler finished and the whole context can be destroyed.
// inside request handler
ctx = new Context(app);
ctx.bind('request').to('request');
// ...
await invoke();
ctx.release();
This may be useful for all objects, not only for expensive resources like database connections. In Fastify, they claim to get ~10% speed up by caching regular objects and functions via https://www.npmjs.com/package/reusify
@bajtos I guess the term singleton
is a bit misleading. Maybe it should be called context-singleton
scope: there is only one instance within the context.
Additionally, it's not ideal to pre-create the singleton and bind it to the context. Singleton instance should be able to leverage dependency injection too. For example:
class Authenticator {
constructor(private @inject('loginProvider') loginProvider,
private @inject('tokenGenerator') tokenGenerator, ...) {
}
}
Closing as done - see #385.
Description/Steps to reproduce
When a dynamic value is bound to the container, there may be different scopes to use the same instance as follows:
Singleton: the bound service is completely stateless and no request dependency (for example, a utility such as password hashing) is needed. For optimal performance/memory footprint, we'll only create the instance once and reuse it within the same context.
Transient: the bound service requires a new instance per request.
Pooled: the bound service (for example, a repository that has a connection pool to a DB) cannot be shared but it's expensive to instantiate/setup. We can maintain a pool of such instances.
See:
Expected result
Additional information