Skip to content

Latest commit

 

History

History
93 lines (68 loc) · 3.11 KB

scopes.md

File metadata and controls

93 lines (68 loc) · 3.11 KB

Services scopes

When you declare a class as a service, you ask the DI container to manage its lifecycle. This is actually done with scopes.

Singletons

By default every declared service is scoped as a singleton. This means that whenever you request it, it will always resolve to the same instance. A singleton service will live as long as your program lives.

@Service({ scoping: SCOPE.singleton }) // optional, it's singleton by default
class SingletonService {
  public readonly sym = Symbol();
}

const container = await getContainer();
console.log(
  container.get(SingletonService) === container.get(SingletonService)
); // true
console.log(
  container.get(SingletonService).sym === container.get(SingletonService).sym
); // true

Renewable

Renewable services will be re-created everythime they are retrieved. This means that doing

@Service({ scoping: 'renewable' })
class RenewableService {
    public readonly sym: Symbol();
}

// ...
console.log(container.get(RenewableService) === container.get(RenewableService)); // false
console.log(container.get(RenewableService).sym === container.get(RenewableService).sym); // false

Custom scoped

The two previous scopes are sometimes not enough to manage services` lifecycles, that's why you can assign custom scopes to your service:

@Service({ scoping: 'custom', customScopes: ['scope1', 'scope2'] })
class CustomScopeService {
   public readonly sym: Symbol();
}

Entering and exiting custom scopes

A custom scope is actually a period of time in which you can enter and from which you can exit. You can do the following with:

const instanceBefore = container.get(CustomScopeService);

// service has no assigned scope overlapping with any running custom scope
container.get(CustomScopeService) === container.get(CustomScopeService); // false

// Enter scope
container.enterScope("scope1");

container.get(CustomScopeService) === container.get(CustomScopeService); // true
container.get(CustomScopeService) === instanceBefore; // false

// Exit scope
container.exitScope("scope1");
  • When you request a service outside of any of it's defined scopes (the ones you assigned to it), custom scopes act as renewable, you'll always receive a new instance.
  • When you request a service inside any of it's defined scopes, you'll receive the same instance.

Overlapping custom scopes

You can have multiple scopes overlapping each other. When a service is assigned multiple scopes which we enter and exit with both overlapping, the service instance is kept alive as long as one of its assigned scope is running. Overlapping scopes

If there's an instance already created in scope1 and we're exiting it, but scope2 is still alive, all services which have both scope1 and scope2 assigned will have their instances kept alive in scope2.

container.enterScope("scope1");
container.enterScope("scope2");
container.exitScope("scope1");
container.exitScope("scope2");

If there are more scopes, the DI system will simply take the first that match to transfer existing instances to.