All quizzesHard
Module Internals — Series 2
Preview — 3 of 10 questions
What capability does DiscoveryModule provide that plain DI does not?
javascript
@Injectable()
export class HandlerRegistry implements OnModuleInit {
constructor(
private readonly discovery: DiscoveryService,
private readonly scanner: MetadataScanner,
private readonly reflector: Reflector,
) {}
onModuleInit() {
for (const wrapper of this.discovery.getProviders()) {
const { instance } = wrapper;
if (!instance || typeof instance !== 'object') continue;
this.scanner.getAllMethodNames(Object.getPrototypeOf(instance))
.forEach(name => {
const meta = this.reflector.get('EVENT_HANDLER', instance[name]);
if (meta) this.register(meta, instance, name);
});
}
}
}AIt replaces the DI container with a service-locator pattern, so providers no longer need to be registered in modules
BIt exposes hidden framework-internal providers that are otherwise unreachable by application code
CIt compiles decorator metadata ahead of time so Reflector lookups become synchronous
DIt lets a provider enumerate every provider and controller instance in the container at runtime, so decorator metadata can be scanned to build a registry without each class explicitly registering itself
Given @SetMetadata('roles', ['admin']) on the class and @SetMetadata('roles', ['editor']) on the handler, and equivalent tags metadata, what do the two calls return?
javascript
const roles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(),
context.getClass(),
]);
const tags = this.reflector.getAllAndMerge<string[]>('tags', [
context.getHandler(),
context.getClass(),
]);Aroles is ['admin', 'editor'] and tags is ['editor'] — the two helpers behave identically apart from ordering
BBoth throw, because metadata defined at two levels is ambiguous
Croles is ['editor'] — the first target in the array that has the key wins — while tags is ['editor', 'admin'], concatenating every level
Droles is ['admin'], because class metadata always takes precedence over handler metadata
Both calls pass structurally identical options. How does Nest decide whether these are one module instance or two?
javascript
@Module({ imports: [ThrottlerModule.forRoot({ ttl: 60, limit: 10 })] })
export class CatsModule {}
@Module({ imports: [ThrottlerModule.forRoot({ ttl: 60, limit: 10 })] })
export class DogsModule {}ADynamic modules are always instantiated once per application, regardless of the options passed
BNest computes a module token from the module class plus a hash of the returned dynamic metadata, so two forRoot() calls producing equivalent metadata resolve to the same cached module instance — differing options would produce distinct tokens and distinct instances
CEach forRoot() call always produces a brand-new module instance, because the returned object is a fresh reference every time
DThe decision is made by the order of the imports arrays — the first registration wins and later ones are discarded silently
Sign up free to play
Answer all 10 questions (7 more), see explanations for every answer, and track your score.