mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
It appears that the intent is to return an unlisten function when `on` is called. The message bus implementations indicate that. However, the `MessageBus` abstract class returns `void` instead. Change to `on: () => void`. PR Close #62898
114 lines
2.9 KiB
TypeScript
114 lines
2.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.dev/license
|
|
*/
|
|
|
|
import {MessageBus} from './message-bus';
|
|
import {Events, Topic} from './messages';
|
|
|
|
type ThrottleTopicDuration = {
|
|
[method in Topic]?: number;
|
|
};
|
|
|
|
type ThrottledTopics = {
|
|
[method in Topic]?: boolean;
|
|
};
|
|
|
|
type TopicsInProgress = {
|
|
[method in Topic]?: boolean;
|
|
};
|
|
|
|
const THROTTLE_METHODS: ThrottleTopicDuration = {
|
|
getLatestComponentExplorerView: 100,
|
|
};
|
|
|
|
type TopicBlockSequence = {
|
|
[method in Topic]?: Topic[];
|
|
};
|
|
|
|
// We can't refresh the view until we've received
|
|
// a response with the latest nested properties.
|
|
const TOPIC_BLOCK_SEQUENCE: TopicBlockSequence = {
|
|
getLatestComponentExplorerView: ['getNestedProperties'],
|
|
};
|
|
|
|
type TopicSequence = {
|
|
[method in Topic]?: Topic;
|
|
};
|
|
|
|
const TOPIC_RESPONSE: TopicSequence = {
|
|
getNestedProperties: 'nestedProperties',
|
|
};
|
|
|
|
const TOPIC_REQUEST: TopicSequence = {
|
|
nestedProperties: 'getNestedProperties',
|
|
};
|
|
|
|
export class PriorityAwareMessageBus extends MessageBus<Events> {
|
|
private _throttled: ThrottledTopics = {};
|
|
private _inProgress: TopicsInProgress = {};
|
|
|
|
constructor(
|
|
private _bus: MessageBus<Events>,
|
|
// Binding is necessary to ensure that `setTimeout` is called in the global context.
|
|
// an doesn't throw "Illegal invocation" error.
|
|
private _setTimeout: typeof setTimeout = setTimeout.bind(globalThis),
|
|
) {
|
|
super();
|
|
}
|
|
|
|
override on<E extends Topic>(topic: E, cb: Events[E]): () => void {
|
|
return this._bus.on(topic, (...args: any) => {
|
|
(cb as any)(...args);
|
|
this._afterMessage(topic);
|
|
});
|
|
}
|
|
|
|
override once<E extends Topic>(topic: E, cb: Events[E]): void {
|
|
return this._bus.once(topic, (...args: any) => {
|
|
(cb as any)(...args);
|
|
this._afterMessage(topic);
|
|
});
|
|
}
|
|
|
|
override emit<E extends Topic>(topic: E, args?: Parameters<Events[E]>): boolean {
|
|
if (this._throttled[topic]) {
|
|
return false;
|
|
}
|
|
if (TOPIC_RESPONSE[topic]) {
|
|
this._inProgress[topic] = true;
|
|
}
|
|
const blockedBy = TOPIC_BLOCK_SEQUENCE[topic];
|
|
if (blockedBy) {
|
|
// The source code here is safe.
|
|
// TypeScript type inference ignores the null check here.
|
|
for (const blocker of blockedBy!) {
|
|
if (this._inProgress[blocker]) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if (THROTTLE_METHODS[topic]) {
|
|
this._throttled[topic] = true;
|
|
this._setTimeout(() => (this._throttled[topic] = false), THROTTLE_METHODS[topic]);
|
|
}
|
|
return this._bus.emit(topic, args);
|
|
}
|
|
|
|
override destroy(): void {
|
|
this._bus.destroy();
|
|
}
|
|
|
|
private _afterMessage(topic: Topic): void {
|
|
const request = TOPIC_REQUEST[topic];
|
|
if (!request) {
|
|
return;
|
|
}
|
|
if (this._inProgress[request]) {
|
|
this._inProgress[request] = false;
|
|
}
|
|
}
|
|
}
|