Skip to content

Commit 384a0d9

Browse files
authoredMar 29, 2019
Performance: use Map for jest-runtime module registry. (#8232)
* Performance: use Map for jest-runtime mock registry. * Update CHANGELOG.md
1 parent e08be02 commit 384a0d9

File tree

3 files changed

+59
-46
lines changed

3 files changed

+59
-46
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
- `[jest-core]` Improve performance of SearchSource.findMatchingTests by 15% ([#8184](https://github.com/facebook/jest/pull/8184))
4747
- `[jest-resolve]` Optimize internal cache lookup performance ([#8183](https://github.com/facebook/jest/pull/8183))
4848
- `[jest-core]` Dramatically improve watch mode performance ([#8201](https://github.com/facebook/jest/pull/8201))
49+
- `[jest-runtime]` Use `Map` instead of `Object` for module registry ([#8232](https://github.com/facebook/jest/pull/8232))
4950

5051
## 24.5.0
5152

‎packages/jest-runtime/src/__tests__/runtime_require_module.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ describe('Runtime requireModule', () => {
132132
});
133133
it('provides `require.main` to modules', () =>
134134
createRuntime(__filename).then(runtime => {
135-
runtime._moduleRegistry[__filename] = module;
135+
runtime._moduleRegistry.set(__filename, module);
136136
[
137137
'./test_root/modules_with_main/export_main.js',
138138
'./test_root/modules_with_main/re_export_main.js',

‎packages/jest-runtime/src/index.ts

+57-45
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ type InternalModuleOptions = {
4747

4848
type InitialModule = Partial<Module> &
4949
Pick<Module, 'children' | 'exports' | 'filename' | 'id' | 'loaded'>;
50-
type ModuleRegistry = {[key: string]: InitialModule | Module};
50+
type ModuleRegistry = Map<string, InitialModule | Module>;
5151
type ResolveOptions = Parameters<typeof require.resolve>[1];
5252

5353
type BooleanObject = {[key: string]: boolean};
@@ -93,8 +93,8 @@ class Runtime {
9393
private _mockMetaDataCache: {
9494
[key: string]: MockFunctionMetadata<unknown, Array<unknown>>;
9595
};
96-
private _mockRegistry: {[key: string]: any};
97-
private _isolatedMockRegistry: {[key: string]: any} | null;
96+
private _mockRegistry: Map<string, any>;
97+
private _isolatedMockRegistry: Map<string, any> | null;
9898
private _moduleMocker: typeof jestMock;
9999
private _isolatedModuleRegistry: ModuleRegistry | null;
100100
private _moduleRegistry: ModuleRegistry;
@@ -127,15 +127,15 @@ class Runtime {
127127
this._currentlyExecutingModulePath = '';
128128
this._environment = environment;
129129
this._explicitShouldMock = Object.create(null);
130-
this._internalModuleRegistry = Object.create(null);
130+
this._internalModuleRegistry = new Map();
131131
this._isCurrentlyExecutingManualMock = null;
132132
this._mockFactories = Object.create(null);
133-
this._mockRegistry = Object.create(null);
133+
this._mockRegistry = new Map();
134134
// during setup, this cannot be null (and it's fine to explode if it is)
135135
this._moduleMocker = this._environment.moduleMocker!;
136136
this._isolatedModuleRegistry = null;
137137
this._isolatedMockRegistry = null;
138-
this._moduleRegistry = Object.create(null);
138+
this._moduleRegistry = new Map();
139139
this._needsCoverageMapped = new Set();
140140
this._resolver = resolver;
141141
this._scriptTransformer = new ScriptTransformer(config);
@@ -291,7 +291,7 @@ class Runtime {
291291
from,
292292
moduleName,
293293
);
294-
let modulePath;
294+
let modulePath: string | undefined;
295295

296296
// Some old tests rely on this mocking behavior. Ideally we'll change this
297297
// to be more explicit.
@@ -320,7 +320,10 @@ class Runtime {
320320
let moduleRegistry;
321321

322322
if (!options || !options.isInternalModule) {
323-
if (this._moduleRegistry[modulePath] || !this._isolatedModuleRegistry) {
323+
if (
324+
this._moduleRegistry.get(modulePath) ||
325+
!this._isolatedModuleRegistry
326+
) {
324327
moduleRegistry = this._moduleRegistry;
325328
} else {
326329
moduleRegistry = this._isolatedModuleRegistry;
@@ -329,29 +332,33 @@ class Runtime {
329332
moduleRegistry = this._internalModuleRegistry;
330333
}
331334

332-
if (!moduleRegistry[modulePath]) {
333-
// We must register the pre-allocated module object first so that any
334-
// circular dependencies that may arise while evaluating the module can
335-
// be satisfied.
336-
const localModule: InitialModule = {
337-
children: [],
338-
exports: {},
339-
filename: modulePath,
340-
id: modulePath,
341-
loaded: false,
342-
};
343-
moduleRegistry[modulePath] = localModule;
344-
345-
this._loadModule(
346-
localModule,
347-
from,
348-
moduleName,
349-
modulePath,
350-
options,
351-
moduleRegistry,
352-
);
335+
const module = moduleRegistry.get(modulePath);
336+
if (module) {
337+
return module.exports;
353338
}
354-
return moduleRegistry[modulePath].exports;
339+
340+
// We must register the pre-allocated module object first so that any
341+
// circular dependencies that may arise while evaluating the module can
342+
// be satisfied.
343+
const localModule: InitialModule = {
344+
children: [],
345+
exports: {},
346+
filename: modulePath,
347+
id: modulePath,
348+
loaded: false,
349+
};
350+
moduleRegistry.set(modulePath, localModule);
351+
352+
this._loadModule(
353+
localModule,
354+
from,
355+
moduleName,
356+
modulePath,
357+
options,
358+
moduleRegistry,
359+
);
360+
361+
return localModule.exports;
355362
}
356363

357364
requireInternalModule(from: Config.Path, to?: string) {
@@ -369,16 +376,21 @@ class Runtime {
369376
moduleName,
370377
);
371378

372-
if (this._isolatedMockRegistry && this._isolatedMockRegistry[moduleID]) {
373-
return this._isolatedMockRegistry[moduleID];
374-
} else if (this._mockRegistry[moduleID]) {
375-
return this._mockRegistry[moduleID];
379+
if (
380+
this._isolatedMockRegistry &&
381+
this._isolatedMockRegistry.get(moduleID)
382+
) {
383+
return this._isolatedMockRegistry.get(moduleID);
384+
} else if (this._mockRegistry.get(moduleID)) {
385+
return this._mockRegistry.get(moduleID);
376386
}
377387

378388
const mockRegistry = this._isolatedMockRegistry || this._mockRegistry;
379389

380390
if (moduleID in this._mockFactories) {
381-
return (mockRegistry[moduleID] = this._mockFactories[moduleID]());
391+
const module = this._mockFactories[moduleID]();
392+
mockRegistry.set(moduleID, module);
393+
return module;
382394
}
383395

384396
const manualMockOrStub = this._resolver.getMockModule(from, moduleName);
@@ -435,13 +447,13 @@ class Runtime {
435447
mockRegistry,
436448
);
437449

438-
mockRegistry[moduleID] = localModule.exports;
450+
mockRegistry.set(moduleID, localModule.exports);
439451
} else {
440452
// Look for a real module to generate an automock from
441-
mockRegistry[moduleID] = this._generateMock(from, moduleName);
453+
mockRegistry.set(moduleID, this._generateMock(from, moduleName));
442454
}
443455

444-
return mockRegistry[moduleID];
456+
return mockRegistry.get(moduleID);
445457
}
446458

447459
private _loadModule(
@@ -495,8 +507,8 @@ class Runtime {
495507
'isolateModules cannot be nested inside another isolateModules.',
496508
);
497509
}
498-
this._isolatedModuleRegistry = Object.create(null);
499-
this._isolatedMockRegistry = Object.create(null);
510+
this._isolatedModuleRegistry = new Map();
511+
this._isolatedMockRegistry = new Map();
500512
fn();
501513
this._isolatedModuleRegistry = null;
502514
this._isolatedMockRegistry = null;
@@ -505,8 +517,8 @@ class Runtime {
505517
resetModules() {
506518
this._isolatedModuleRegistry = null;
507519
this._isolatedMockRegistry = null;
508-
this._mockRegistry = Object.create(null);
509-
this._moduleRegistry = Object.create(null);
520+
this._mockRegistry = new Map();
521+
this._moduleRegistry = new Map();
510522

511523
if (this._environment) {
512524
if (this._environment.global) {
@@ -678,7 +690,7 @@ class Runtime {
678690
enumerable: true,
679691
get() {
680692
const key = from || '';
681-
return moduleRegistry[key] || null;
693+
return moduleRegistry.get(key) || null;
682694
},
683695
});
684696

@@ -770,8 +782,8 @@ class Runtime {
770782
// mocked has calls into side-effectful APIs on another module.
771783
const origMockRegistry = this._mockRegistry;
772784
const origModuleRegistry = this._moduleRegistry;
773-
this._mockRegistry = Object.create(null);
774-
this._moduleRegistry = Object.create(null);
785+
this._mockRegistry = new Map();
786+
this._moduleRegistry = new Map();
775787

776788
const moduleExports = this.requireModule(from, moduleName);
777789

0 commit comments

Comments
 (0)
Please sign in to comment.