From 121c8e3f04621983760db1db3276a65514ccbe0b Mon Sep 17 00:00:00 2001 From: Wenzhao Hu <12122021+wzhudev@users.noreply.github.com> Date: Fri, 7 Feb 2025 15:58:00 +0800 Subject: [PATCH] fix: fix render unit and interceptor memory leak --- .../render-manager/render-manager.service.ts | 1 + .../src/render-manager/render-unit.ts | 9 -- .../canvas-float-dom-manager.service.ts | 27 ++-- .../controllers/sheets-filter.controller.ts | 6 +- .../sheets-filter/src/models/filter-model.ts | 3 +- .../src/controllers/auto-fill.controller.ts | 123 ++++++++---------- .../clipboard/clipboard.controller.ts | 3 +- .../sheet-permission-render.controller.ts | 7 +- .../sheet-skeleton-manager.service.ts | 1 + .../views/clipboard/ClipboardPopupMenu.tsx | 3 +- .../src/model/range-protection-rule.model.ts | 25 ++-- .../sheet-interceptor.service.ts | 24 ++-- 12 files changed, 113 insertions(+), 119 deletions(-) diff --git a/packages/engine-render/src/render-manager/render-manager.service.ts b/packages/engine-render/src/render-manager/render-manager.service.ts index 92432104cb3..3333202f607 100644 --- a/packages/engine-render/src/render-manager/render-manager.service.ts +++ b/packages/engine-render/src/render-manager/render-manager.service.ts @@ -56,6 +56,7 @@ export interface IRenderManagerService extends IDisposable { getRenderUnitById(unitId: string): Nullable; getAllRenderersOfType(type: UniverInstanceType): RenderUnit[]; getCurrentTypeOfRenderer(type: UniverInstanceType): Nullable; + getCurrentTypeOfRenderer$(type: UniverInstanceType): Observable>; getRenderAll(): Map; defaultEngine: Engine; diff --git a/packages/engine-render/src/render-manager/render-unit.ts b/packages/engine-render/src/render-manager/render-unit.ts index 31d9c6e1b27..8a037145b33 100644 --- a/packages/engine-render/src/render-manager/render-unit.ts +++ b/packages/engine-render/src/render-manager/render-unit.ts @@ -128,15 +128,6 @@ export class RenderUnit extends Disposable implements IRender { this._activated$.next(false); this._activated$.complete(); - - // Avoid memory leak. Basically it is because RenderUnit itself is leaking. - // We use this as a temporary solution to make CI pass. - // @ts-ignore - this._renderContext.activated$ = null; - // @ts-ignore - this._renderContext.activate = null; - // @ts-ignore - this._renderContext.deactivate = null; } /** diff --git a/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts b/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts index 18e2688602a..57e83766f4c 100644 --- a/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts +++ b/packages/sheets-drawing-ui/src/services/canvas-float-dom-manager.service.ts @@ -28,7 +28,7 @@ import { COMMAND_LISTENER_SKELETON_CHANGE, getSheetCommandTarget, SetFrozenMutat import { DrawingApplyType, ISheetDrawingService, SetDrawingApplyMutation } from '@univerjs/sheets-drawing'; import { ISheetSelectionRenderService, SetScrollOperation, SetZoomRatioOperation, SheetSkeletonManagerService } from '@univerjs/sheets-ui'; import { CanvasFloatDomService } from '@univerjs/ui'; -import { BehaviorSubject, filter, map, Subject, switchMap, take } from 'rxjs'; +import { BehaviorSubject, filter, map, of, Subject, switchMap, take } from 'rxjs'; import { InsertSheetDrawingCommand } from '../commands/commands/insert-sheet-drawing.command'; export interface ICanvasFloatDom { @@ -516,22 +516,27 @@ export class SheetCanvasFloatDomManagerService extends Disposable { // #region scroll this.disposeWithMe( this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET).pipe( - filter((workbook) => !!workbook), - switchMap((workbook) => workbook.activeSheet$), - filter((sheet) => !!sheet), - map((sheet) => { - const render = this._renderManagerService.getRenderById(sheet.getUnitId()); - return render ? { render, unitId: sheet.getUnitId(), subUnitId: sheet.getSheetId() } : null; + switchMap((workbook) => workbook ? workbook.activeSheet$ : of(null)), + map((worksheet) => { + if (!worksheet) return null; + const unitId = worksheet.getUnitId(); + const render = this._renderManagerService.getRenderById(unitId); + return render ? { render, unitId, subUnitId: worksheet.getSheetId() } : null; }), - filter((render) => !!render), switchMap((render) => - fromEventSubject(render.render.scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!.onScrollAfter$) - .pipe(map(() => ({ unitId: render.unitId, subUnitId: render.subUnitId }))) + render + ? fromEventSubject(render.render.scene.getViewport(SHEET_VIEWPORT_KEY.VIEW_MAIN)!.onScrollAfter$) + .pipe(map(() => ({ unitId: render.unitId, subUnitId: render.subUnitId }))) + : of(null) ) - ).subscribe(({ unitId, subUnitId }) => { + ).subscribe((value) => { + if (!value) return; // TODO@weird94: maybe we should throw an error here and do some cleaning work? + + const { unitId, subUnitId } = value; updateSheet(unitId, subUnitId); }) ); + //#endregion // #region zoom diff --git a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts index 9157af40684..eecb6e5b744 100644 --- a/packages/sheets-filter/src/controllers/sheets-filter.controller.ts +++ b/packages/sheets-filter/src/controllers/sheets-filter.controller.ts @@ -199,7 +199,7 @@ export class SheetsFilterController extends Disposable { const filterColumn = filterModel.getAllFilterColumns(); const effected = filterColumn.filter((column) => column[0] >= anchor); if (effected.length !== 0) { - const { newRange, oldRange } = this.moveCriteria(unitId, subUnitId, effected, count); + const { newRange, oldRange } = this._moveCriteria(unitId, subUnitId, effected, count); redos.push(...newRange.redos, ...oldRange.redos); undos.push(...newRange.undos, ...oldRange.undos); } @@ -281,7 +281,7 @@ export class SheetsFilterController extends Disposable { let newRangeCriteria: { undos: IMutationInfo[]; redos: IMutationInfo[] } = { undos: [], redos: [] }; if (shifted.length > 0) { - const { oldRange, newRange } = this.moveCriteria(unitId, subUnitId, shifted, -removeCount); + const { oldRange, newRange } = this._moveCriteria(unitId, subUnitId, shifted, -removeCount); newRangeCriteria = newRange; redos.push(...oldRange.redos); undos.unshift(...oldRange.undos); @@ -693,7 +693,7 @@ export class SheetsFilterController extends Disposable { })); } - private moveCriteria(unitId: string, subUnitId: string, target: [number, FilterColumn][], step: number) { + private _moveCriteria(unitId: string, subUnitId: string, target: [number, FilterColumn][], step: number) { const defaultSetCriteriaMutationParams: ISetSheetsFilterCriteriaMutationParams = { unitId, subUnitId, diff --git a/packages/sheets-filter/src/models/filter-model.ts b/packages/sheets-filter/src/models/filter-model.ts index bf8c9406472..3de2a8471cc 100644 --- a/packages/sheets-filter/src/models/filter-model.ts +++ b/packages/sheets-filter/src/models/filter-model.ts @@ -16,10 +16,11 @@ import type { CellValue, ICellData, IRange, Nullable, Worksheet } from '@univerjs/core'; import type { Observable } from 'rxjs'; +import type { IAutoFilter, ICustomFilter, ICustomFilters, IFilterColumn, IFilters } from './types'; import { CellValueType, Disposable, extractPureTextFromCell, mergeSets, Rectangle, Tools } from '@univerjs/core'; import { BehaviorSubject } from 'rxjs'; import { ensureNumeric, getCustomFilterFn, isNumericFilterFn, notEquals } from './custom-filters'; -import { CustomFilterOperator, type IAutoFilter, type ICustomFilter, type ICustomFilters, type IFilterColumn, type IFilters } from './types'; +import { CustomFilterOperator } from './types'; const EMPTY = () => new Set(); diff --git a/packages/sheets-ui/src/controllers/auto-fill.controller.ts b/packages/sheets-ui/src/controllers/auto-fill.controller.ts index c91600a23db..90474d3749c 100644 --- a/packages/sheets-ui/src/controllers/auto-fill.controller.ts +++ b/packages/sheets-ui/src/controllers/auto-fill.controller.ts @@ -40,7 +40,6 @@ import { IUniverInstanceService, ObjectMatrix, Rectangle, - toDisposable, Tools, UniverInstanceType, } from '@univerjs/core'; @@ -113,7 +112,7 @@ export class AutoFillController extends Disposable { private _init() { this._initDefaultHook(); - this._onSelectionControlFillChanged(); + this._initSelectionControlFillChanged(); this._initQuitListener(); this._initSkeletonChange(); } @@ -179,11 +178,10 @@ export class AutoFillController extends Disposable { this._autoFillService.setShowMenu(false); } - // eslint-disable-next-line max-lines-per-function - private _onSelectionControlFillChanged() { + private _initSelectionControlFillChanged() { const disposableCollection = new DisposableCollection(); - const addListener = (disposableCollection: DisposableCollection) => { - // Each range change requires re-listening + const updateListener = () => { + // Each range change requires re-listening. disposableCollection.dispose(); const currentRenderer = this._renderManagerService.getCurrentTypeOfRenderer(UniverInstanceType.UNIVER_SHEET); @@ -192,78 +190,69 @@ export class AutoFillController extends Disposable { const selectionRenderService = currentRenderer.with(ISheetSelectionRenderService); const selectionControls = selectionRenderService.getSelectionControls(); selectionControls.forEach((controlSelection) => { - disposableCollection.add( - toDisposable( - controlSelection.selectionFilled$.subscribe((filled) => { - if ( - filled == null || + disposableCollection.add(controlSelection.selectionFilled$.subscribe((filled) => { + if ( + filled == null || filled.startColumn === -1 || filled.startRow === -1 || filled.endColumn === -1 || filled.endRow === -1 - ) { - return; - } - const source: IRange = { - startColumn: controlSelection.model.startColumn, - endColumn: controlSelection.model.endColumn, - startRow: controlSelection.model.startRow, - endRow: controlSelection.model.endRow, - }; - const selection: IRange = { - startColumn: filled.startColumn, - endColumn: filled.endColumn, - startRow: filled.startRow, - endRow: filled.endRow, - }; - - this._commandService.executeCommand(AutoFillCommand.id, { sourceRange: source, targetRange: selection }); - }) - ) - ); + ) { + return; + } + const source: IRange = { + startColumn: controlSelection.model.startColumn, + endColumn: controlSelection.model.endColumn, + startRow: controlSelection.model.startRow, + endRow: controlSelection.model.endRow, + }; + const selection: IRange = { + startColumn: filled.startColumn, + endColumn: filled.endColumn, + startRow: filled.startRow, + endRow: filled.endRow, + }; + + this._commandService.executeCommand(AutoFillCommand.id, { sourceRange: source, targetRange: selection }); + })); // double click to fill range, range length will align to left or right column. // fill results will be as same as drag operation - disposableCollection.add( - toDisposable( - controlSelection.fillControl.onDblclick$.subscribeEvent(() => { - const source = { - startColumn: controlSelection.model.startColumn, - endColumn: controlSelection.model.endColumn, - startRow: controlSelection.model.startRow, - endRow: controlSelection.model.endRow, - }; - this._handleDbClickFill(source); - }) - ) - ); - - disposableCollection.add( - toDisposable( - controlSelection.fillControl.onPointerDown$.subscribeEvent(() => { - const visibleState = this._editorBridgeService.isVisible(); - if (visibleState.visible) { - this._editorBridgeService.changeVisible({ - visible: false, - eventType: DeviceInputEventType.PointerDown, - unitId: currentRenderer.unitId, - }); - } - }) - ) - ); + disposableCollection.add(controlSelection.fillControl.onDblclick$.subscribeEvent(() => { + const source = { + startColumn: controlSelection.model.startColumn, + endColumn: controlSelection.model.endColumn, + startRow: controlSelection.model.startRow, + endRow: controlSelection.model.endRow, + }; + this._handleDbClickFill(source); + })); + + disposableCollection.add(controlSelection.fillControl.onPointerDown$.subscribeEvent(() => { + const visibleState = this._editorBridgeService.isVisible(); + if (visibleState.visible) { + this._editorBridgeService.changeVisible({ + visible: false, + eventType: DeviceInputEventType.PointerDown, + unitId: currentRenderer.unitId, + }); + } + })); }); }; - addListener(disposableCollection); + updateListener(); - this.disposeWithMe( - this._commandService.onCommandExecuted((command: ICommandInfo) => { - if (command.id === SetSelectionsOperation.id) { - addListener(disposableCollection); - } - }) - ); + // Should subscribe current current renderer change as well. + // TODO@yuhongz: this seems not ideal. This should be an `IRenderModule` for running with multiple renderers? + this.disposeWithMe(this._commandService.onCommandExecuted((command: ICommandInfo) => { + if (command.id === SetSelectionsOperation.id) { + updateListener(); + } + })); + + this.disposeWithMe(this._univerInstanceService.getCurrentTypeOfUnit$(UniverInstanceType.UNIVER_SHEET) + .subscribe(() => updateListener())); } private _handleDbClickFill(source: IRange) { diff --git a/packages/sheets-ui/src/controllers/clipboard/clipboard.controller.ts b/packages/sheets-ui/src/controllers/clipboard/clipboard.controller.ts index 59e9ec029b8..b0a233eb744 100644 --- a/packages/sheets-ui/src/controllers/clipboard/clipboard.controller.ts +++ b/packages/sheets-ui/src/controllers/clipboard/clipboard.controller.ts @@ -148,7 +148,7 @@ export class SheetClipboardController extends RxDisposable { super(); this._init(); this._initCommandListener(); - this._initUIComponents(); + // this._initUIComponents(); this._pasteWithDoc(); } @@ -913,6 +913,7 @@ export class SheetClipboardController extends RxDisposable { if (sheetsUIConfig?.clipboardConfig?.hidePasteOptions) { return; } + this.disposeWithMe( this._uiPartsService.registerComponent(BuiltInUIPart.CONTENT, () => connectInjector(ClipboardPopupMenu, this._injector)) ); diff --git a/packages/sheets-ui/src/controllers/permission/sheet-permission-render.controller.ts b/packages/sheets-ui/src/controllers/permission/sheet-permission-render.controller.ts index 5271e9fa81c..3817cb07556 100644 --- a/packages/sheets-ui/src/controllers/permission/sheet-permission-render.controller.ts +++ b/packages/sheets-ui/src/controllers/permission/sheet-permission-render.controller.ts @@ -16,6 +16,7 @@ import type { IRenderContext, IRenderModule, Spreadsheet } from '@univerjs/engine-render'; import type { MenuConfig } from '@univerjs/ui'; +import type { IUniverSheetsUIConfig } from '../config.schema'; import { connectInjector, Disposable, IConfigService, Inject, Injector, IPermissionService, IUniverInstanceService } from '@univerjs/core'; import { IRenderManagerService } from '@univerjs/engine-render'; import { CheckMarkSingle, DeleteSingle, LockSingle, ProtectSingle, WriteSingle } from '@univerjs/icons'; @@ -30,7 +31,7 @@ import { UNIVER_SHEET_PERMISSION_ALERT_DIALOG } from '../../views/permission/err import { RANGE_PROTECTION_CAN_NOT_VIEW_RENDER_EXTENSION_KEY, RANGE_PROTECTION_CAN_VIEW_RENDER_EXTENSION_KEY, RangeProtectionCanNotViewRenderExtension, RangeProtectionCanViewRenderExtension } from '../../views/permission/extensions/range-protection.render'; import { worksheetProtectionKey, WorksheetProtectionRenderExtension } from '../../views/permission/extensions/worksheet-permission.render'; import { PermissionDetailUserPart } from '../../views/permission/panel-detail/PermissionDetailUserPart'; -import { type IUniverSheetsUIConfig, SHEETS_UI_PLUGIN_CONFIG_KEY } from '../config.schema'; +import { SHEETS_UI_PLUGIN_CONFIG_KEY } from '../config.schema'; export interface IUniverSheetsPermissionMenuConfig { menu: MenuConfig; @@ -99,14 +100,14 @@ export class SheetPermissionRenderController extends Disposable implements IRend this._initRender(); this._initSkeleton(); - this._rangeProtectionRuleModel.ruleChange$.subscribe((info) => { + this.disposeWithMe(this._rangeProtectionRuleModel.ruleChange$.subscribe((info) => { if ((info.oldRule?.id && this._rangeProtectionCanViewRenderExtension.renderCache.has(info.oldRule.id)) || this._rangeProtectionCanViewRenderExtension.renderCache.has(info.rule.id)) { this._rangeProtectionCanViewRenderExtension.clearCache(); } if ((info.oldRule?.id && this._rangeProtectionCanNotViewRenderExtension.renderCache.has(info.oldRule.id)) || this._rangeProtectionCanNotViewRenderExtension.renderCache.has(info.rule.id)) { this._rangeProtectionCanNotViewRenderExtension.clearCache(); } - }); + })); } private _initRender(): void { diff --git a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts index df0cc75c7c8..bf3ec97cb3d 100644 --- a/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts +++ b/packages/sheets-ui/src/services/sheet-skeleton-manager.service.ts @@ -68,6 +68,7 @@ export class SheetSkeletonManagerService extends Disposable implements IRenderMo this._currentSkeletonBefore$.complete(); this._currentSkeleton$.complete(); this._sheetSkeletonParamStore = new Map(); + this._sheetSkService.deleteSkeleton(this._context.unitId, this._sheetId); }); this._initRemoveSheet(); diff --git a/packages/sheets-ui/src/views/clipboard/ClipboardPopupMenu.tsx b/packages/sheets-ui/src/views/clipboard/ClipboardPopupMenu.tsx index c706ba7c4b8..654a73a75fb 100644 --- a/packages/sheets-ui/src/views/clipboard/ClipboardPopupMenu.tsx +++ b/packages/sheets-ui/src/views/clipboard/ClipboardPopupMenu.tsx @@ -22,7 +22,7 @@ import { DropdownOverlay, DropdownProvider, DropdownTrigger } from '@univerjs/de import { convertTransformToOffsetX, convertTransformToOffsetY, IRenderManagerService } from '@univerjs/engine-render'; import { CheckMarkSingle, MoreDownSingle, PasteSpecial } from '@univerjs/icons'; import clsx from 'clsx'; -import React, { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { SheetOptionalPasteCommand } from '../../commands/commands/clipboard.command'; import { SetScrollOperation } from '../../commands/operations/scroll.operation'; import { useActiveWorkbook, useSheetSkeleton } from '../../components/hook'; @@ -113,7 +113,6 @@ export const ClipboardPopupMenu = () => { const clipboardService = useDependency(ISheetClipboardService); const showMenu = useObservable(clipboardService.showMenu$, true); const pasteOptionsCache = useObservable(clipboardService.pasteOptionsCache$, null); - const renderManagerService = useDependency(IRenderManagerService); const localeService = useDependency(LocaleService); const commandService = useDependency(ICommandService); diff --git a/packages/sheets/src/model/range-protection-rule.model.ts b/packages/sheets/src/model/range-protection-rule.model.ts index eaab96f7d7d..b6de2b38aff 100644 --- a/packages/sheets/src/model/range-protection-rule.model.ts +++ b/packages/sheets/src/model/range-protection-rule.model.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import type { IRange } from '@univerjs/core'; +import type { IDisposable, IRange } from '@univerjs/core'; import type { UnitObject } from '@univerjs/protocol'; import { Tools } from '@univerjs/core'; @@ -55,22 +55,25 @@ export interface IRuleChange { type IRuleChangeType = 'add' | 'set' | 'delete'; -export class RangeProtectionRuleModel { +export class RangeProtectionRuleModel implements IDisposable { /** - * * Map>> */ private _model: IModel = new Map(); - private _ruleChange = new Subject(); + private readonly _ruleChange$ = new Subject(); + readonly ruleChange$ = this._ruleChange$.asObservable(); - ruleChange$ = this._ruleChange.asObservable(); + private _ruleRefresh$ = new Subject(); + ruleRefresh$ = this._ruleRefresh$.asObservable(); - private _ruleRefresh = new Subject(); - ruleRefresh$ = this._ruleRefresh.asObservable(); + dispose(): void { + this._ruleChange$.complete(); + this._ruleRefresh$.complete(); + } ruleRefresh(id: string) { - this._ruleRefresh.next(id); + this._ruleRefresh$.next(id); } private _rangeRuleInitStateChange = new BehaviorSubject(false); @@ -87,14 +90,14 @@ export class RangeProtectionRuleModel { addRule(unitId: string, subUnitId: string, rule: IRangeProtectionRule) { const ruleMap = this._ensureRuleMap(unitId, subUnitId); ruleMap.set(rule.id, rule); - this._ruleChange.next({ unitId, subUnitId, rule, type: 'add' }); + this._ruleChange$.next({ unitId, subUnitId, rule, type: 'add' }); } deleteRule(unitId: string, subUnitId: string, id: string) { const rule = this._model.get(unitId)?.get(subUnitId)?.get(id); if (rule) { this._model.get(unitId)?.get(subUnitId)?.delete(id); - this._ruleChange.next({ unitId, subUnitId, rule, type: 'delete' }); + this._ruleChange$.next({ unitId, subUnitId, rule, type: 'delete' }); } } @@ -102,7 +105,7 @@ export class RangeProtectionRuleModel { const oldRule = this.getRule(unitId, subUnitId, id); if (oldRule) { this._model.get(unitId)?.get(subUnitId)?.set(id, rule); - this._ruleChange.next({ unitId, subUnitId, oldRule, rule, type: 'set' }); + this._ruleChange$.next({ unitId, subUnitId, oldRule, rule, type: 'set' }); } } diff --git a/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts b/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts index 0bd4a5ce41a..bc3a746ab09 100644 --- a/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts +++ b/packages/sheets/src/services/sheet-interceptor/sheet-interceptor.service.ts @@ -305,11 +305,11 @@ export class SheetInterceptorService extends Disposable { interceptors.push(interceptor); const sortedInterceptors = interceptors.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0)); + this._interceptorsDirty = true; + if (key === INTERCEPTOR_POINT.CELL_CONTENT as unknown as string) { - this._interceptorsByName.set( - `${key}-${(InterceptorEffectEnum.Style | InterceptorEffectEnum.Value)}`, - sortedInterceptors - ); + const JOINED_EFFECT = InterceptorEffectEnum.Style | InterceptorEffectEnum.Value; + this._interceptorsByName.set(`${key}-${JOINED_EFFECT}`, sortedInterceptors); const BOTH_EFFECT = InterceptorEffectEnum.Style | InterceptorEffectEnum.Value; this._interceptorsByName.set( @@ -320,15 +320,17 @@ export class SheetInterceptorService extends Disposable { `${key}-${(InterceptorEffectEnum.Value)}`, (sortedInterceptors as ICellInterceptor[]).filter((i) => ((i.effect || BOTH_EFFECT) & InterceptorEffectEnum.Value) > 0) ); + + return this.disposeWithMe(toDisposable(() => { + remove(this._interceptorsByName.get(key)!, interceptor); + remove(this._interceptorsByName.get(`${key}-${JOINED_EFFECT}`)!, interceptor); + remove(this._interceptorsByName.get(`${key}-${(InterceptorEffectEnum.Style)}`)!, interceptor); + remove(this._interceptorsByName.get(`${key}-${(InterceptorEffectEnum.Value)}`)!, interceptor); + })); } else { - this._interceptorsByName.set( - key, - sortedInterceptors - ); + this._interceptorsByName.set(key, sortedInterceptors); + return this.disposeWithMe(toDisposable(() => remove(this._interceptorsByName.get(key)!, interceptor))); } - - this._interceptorsDirty = true; - return this.disposeWithMe(toDisposable(() => remove(this._interceptorsByName.get(key)!, interceptor))); } fetchThroughInterceptors(