src/vs/platform/actions/common/menuService.ts/MenuImpl/constructor
class MenuImpl:	constructor(
		id: MenuId,
		hiddenStates: PersistedMenuHideState,
		options: Required<IMenuCreateOptions>,
		@ICommandService commandService: ICommandService,
		@IContextKeyService contextKeyService: IContextKeyService,
	) {
		this._menuInfo = new MenuInfo(id, hiddenStates, options.emitEventsForSubmenuChanges, commandService, contextKeyService);

		// Rebuild this menu whenever the menu registry reports an event for this MenuId.
		// This usually happen while code and extensions are loaded and affects the over
		// structure of the menu
		const rebuildMenuSoon = new RunOnceScheduler(() => {
			this._menuInfo.refresh();
			this._onDidChange.fire({ menu: this, isStructuralChange: true, isEnablementChange: true, isToggleChange: true });
		}, options.eventDebounceDelay);
		this._disposables.add(rebuildMenuSoon);
		this._disposables.add(MenuRegistry.onDidChangeMenu(e => {
			if (e.has(id)) {
				rebuildMenuSoon.schedule();
			}
		}));

		// When context keys or storage state changes we need to check if the menu also has changed. However,
		// we only do that when someone listens on this menu because (1) these events are
		// firing often and (2) menu are often leaked
		const lazyListener = this._disposables.add(new DisposableStore());

		const merge = (events: IMenuChangeEvent[]): IMenuChangeEvent => {

			let isStructuralChange = false;
			let isEnablementChange = false;
			let isToggleChange = false;

			for (const item of events) {
				isStructuralChange = isStructuralChange || item.isStructuralChange;
				isEnablementChange = isEnablementChange || item.isEnablementChange;
				isToggleChange = isToggleChange || item.isToggleChange;
				if (isStructuralChange && isEnablementChange && isToggleChange) {
					// everything is TRUE, no need to continue iterating
					break;
				}
			}

			return { menu: this, isStructuralChange, isEnablementChange, isToggleChange };
		};

		const startLazyListener = () => {

			lazyListener.add(contextKeyService.onDidChangeContext(e => {
				const isStructuralChange = e.affectsSome(this._menuInfo.structureContextKeys);
				const isEnablementChange = e.affectsSome(this._menuInfo.preconditionContextKeys);
				const isToggleChange = e.affectsSome(this._menuInfo.toggledContextKeys);
				if (isStructuralChange || isEnablementChange || isToggleChange) {
					this._onDidChange.fire({ menu: this, isStructuralChange, isEnablementChange, isToggleChange });
				}
			}));
			lazyListener.add(hiddenStates.onDidChange(e => {
				this._onDidChange.fire({ menu: this, isStructuralChange: true, isEnablementChange: false, isToggleChange: false });
			}));
		};

		this._onDidChange = new DebounceEmitter({
			// start/stop context key listener
			onWillAddFirstListener: startLazyListener,
			onDidRemoveLastListener: lazyListener.clear.bind(lazyListener),
			delay: options.eventDebounceDelay,
			merge
		});
		this.onDidChange = this._onDidChange.event;
	}