fix(language-service): create StaticReflector once only (#32543)
The creation of StaticReflector in createMetadataResolver() is a very expensive operation because it involves numerous module resolutions. To make matter worse, since the API of the Reflector does not provide the ability to invalidate its internal caches, it has to be destroyed and recreated on *every* program change. This has a HUGE impact on performance. This PR fixes this problem by carefully invalidating all StaticSymbols in a file that has changed, thereby reducing the overhead of recomputation on program change. PR Close #32543
This commit is contained in:
@ -86,6 +86,22 @@ export class StaticReflector implements CompileReflector {
|
||||
return this.symbolResolver.getResourcePath(staticSymbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate the specified `symbols` on program change.
|
||||
* @param symbols
|
||||
*/
|
||||
invalidateSymbols(symbols: StaticSymbol[]) {
|
||||
for (const symbol of symbols) {
|
||||
this.annotationCache.delete(symbol);
|
||||
this.shallowAnnotationCache.delete(symbol);
|
||||
this.propertyCache.delete(symbol);
|
||||
this.parameterCache.delete(symbol);
|
||||
this.methodCache.delete(symbol);
|
||||
this.staticCache.delete(symbol);
|
||||
this.conversionMap.delete(symbol);
|
||||
}
|
||||
}
|
||||
|
||||
resolveExternalReference(ref: o.ExternalReference, containingFile?: string): StaticSymbol {
|
||||
let key: string|undefined = undefined;
|
||||
if (!containingFile) {
|
||||
|
@ -63,7 +63,6 @@ export class StaticSymbolResolver {
|
||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||
// Note: this will only contain StaticSymbols without members!
|
||||
private resolvedSymbols = new Map<StaticSymbol, ResolvedStaticSymbol>();
|
||||
private resolvedFilePaths = new Set<string>();
|
||||
// Note: this will only contain StaticSymbols without members!
|
||||
private importAs = new Map<StaticSymbol, StaticSymbol>();
|
||||
private symbolResourcePaths = new Map<StaticSymbol, string>();
|
||||
@ -176,22 +175,24 @@ export class StaticSymbolResolver {
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate all information derived from the given file.
|
||||
* Invalidate all information derived from the given file and return the
|
||||
* static symbols contained in the file.
|
||||
*
|
||||
* @param fileName the file to invalidate
|
||||
*/
|
||||
invalidateFile(fileName: string) {
|
||||
invalidateFile(fileName: string): StaticSymbol[] {
|
||||
this.metadataCache.delete(fileName);
|
||||
this.resolvedFilePaths.delete(fileName);
|
||||
const symbols = this.symbolFromFile.get(fileName);
|
||||
if (symbols) {
|
||||
this.symbolFromFile.delete(fileName);
|
||||
for (const symbol of symbols) {
|
||||
this.resolvedSymbols.delete(symbol);
|
||||
this.importAs.delete(symbol);
|
||||
this.symbolResourcePaths.delete(symbol);
|
||||
}
|
||||
if (!symbols) {
|
||||
return [];
|
||||
}
|
||||
this.symbolFromFile.delete(fileName);
|
||||
for (const symbol of symbols) {
|
||||
this.resolvedSymbols.delete(symbol);
|
||||
this.importAs.delete(symbol);
|
||||
this.symbolResourcePaths.delete(symbol);
|
||||
}
|
||||
return symbols;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@ -277,10 +278,9 @@ export class StaticSymbolResolver {
|
||||
}
|
||||
|
||||
private _createSymbolsOf(filePath: string) {
|
||||
if (this.resolvedFilePaths.has(filePath)) {
|
||||
if (this.symbolFromFile.has(filePath)) {
|
||||
return;
|
||||
}
|
||||
this.resolvedFilePaths.add(filePath);
|
||||
const resolvedSymbols: ResolvedStaticSymbol[] = [];
|
||||
const metadata = this.getModuleMetadata(filePath);
|
||||
if (metadata['importAs']) {
|
||||
|
Reference in New Issue
Block a user