fix(segmentation): Allow for debounced pub/sub events to be reliably cancelled when unsubscribed to. (#5092)
This commit is contained in:
parent
a1fb7217bd
commit
38ed7ba744
@ -132,6 +132,10 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
},
|
||||
getPanelModule,
|
||||
onModeExit: ({ servicesManager }: withAppTypes): void => {
|
||||
unsubscriptions.forEach(unsubscribe => unsubscribe());
|
||||
// Clear the unsubscriptions
|
||||
unsubscriptions.length = 0;
|
||||
|
||||
const { cineService, segmentationService } = servicesManager.services;
|
||||
// Empty out the image load and retrieval pools to prevent memory leaks
|
||||
// on the mode exits
|
||||
@ -150,10 +154,6 @@ const cornerstoneExtension: Types.Extensions.Extension = {
|
||||
useToggleOneUpViewportGridStore.getState().clearToggleOneUpViewportGridStore();
|
||||
useSegmentationPresentationStore.getState().clearSegmentationPresentationStore();
|
||||
segmentationService.removeAllSegmentations();
|
||||
|
||||
unsubscriptions.forEach(unsubscribe => unsubscribe());
|
||||
// Clear the unsubscriptions
|
||||
unsubscriptions.length = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@ -255,7 +255,7 @@ class SegmentationService extends PubSubService {
|
||||
this._onSegmentationAddedFromSource
|
||||
);
|
||||
|
||||
this.listeners = {};
|
||||
this.reset();
|
||||
};
|
||||
|
||||
public async addSegmentationRepresentation(
|
||||
|
||||
@ -9,7 +9,11 @@ export function setupSegmentationDataModifiedHandler({
|
||||
customizationService,
|
||||
commandsManager,
|
||||
}) {
|
||||
const { unsubscribe } = segmentationService.subscribeDebounced(
|
||||
// A flag to indicate if the event is unsubscribed to. This is important because
|
||||
// the debounced callback does an await and in that period of time the event may have
|
||||
// been unsubscribed.
|
||||
let isUnsubscribed = false;
|
||||
const { unsubscribe: debouncedUnsubscribe } = segmentationService.subscribeDebounced(
|
||||
segmentationService.EVENTS.SEGMENTATION_DATA_MODIFIED,
|
||||
async ({ segmentationId }) => {
|
||||
const segmentation = segmentationService.getSegmentation(segmentationId);
|
||||
@ -42,7 +46,7 @@ export function setupSegmentationDataModifiedHandler({
|
||||
readableText,
|
||||
});
|
||||
|
||||
if (updatedSegmentation) {
|
||||
if (!isUnsubscribed && updatedSegmentation) {
|
||||
segmentationService.addOrUpdateSegmentation({
|
||||
segmentationId,
|
||||
segments: updatedSegmentation.segments,
|
||||
@ -52,6 +56,10 @@ export function setupSegmentationDataModifiedHandler({
|
||||
1000
|
||||
);
|
||||
|
||||
const unsubscribe = () => {
|
||||
isUnsubscribed = true;
|
||||
debouncedUnsubscribe();
|
||||
};
|
||||
return { unsubscribe };
|
||||
}
|
||||
|
||||
|
||||
@ -54,7 +54,10 @@ function _unsubscribe(eventName, listenerId) {
|
||||
|
||||
const listeners = this.listeners[eventName];
|
||||
if (Array.isArray(listeners)) {
|
||||
this.listeners[eventName] = listeners.filter(({ id }) => id !== listenerId);
|
||||
this.listeners[eventName] = listeners.filter(({ id, callback }) => {
|
||||
callback?.clearDebounceTimeout?.();
|
||||
return id !== listenerId;
|
||||
});
|
||||
} else {
|
||||
this.listeners[eventName] = undefined;
|
||||
}
|
||||
@ -134,6 +137,13 @@ export class PubSubService {
|
||||
reset() {
|
||||
this.unsubscriptions.forEach(unsub => unsub());
|
||||
this.unsubscriptions = [];
|
||||
|
||||
Object.keys(this.listeners).forEach(eventName =>
|
||||
this.listeners[eventName].forEach(({ callback }) => {
|
||||
callback?.clearDebounceTimeout?.();
|
||||
})
|
||||
);
|
||||
this.listeners = {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -2,9 +2,11 @@
|
||||
// be triggered. The function will be called after it stops being called for
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
// The callback function returned is assigned a clearDebounceTimeout function
|
||||
// that provides for clearing the timeout/debounced function so that it is not called.
|
||||
function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function () {
|
||||
const callback = function () {
|
||||
var context = this,
|
||||
args = arguments;
|
||||
var later = function () {
|
||||
@ -20,6 +22,13 @@ function debounce(func, wait, immediate) {
|
||||
func.apply(context, args);
|
||||
}
|
||||
};
|
||||
|
||||
callback.clearDebounceTimeout = () => {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
};
|
||||
|
||||
return callback;
|
||||
}
|
||||
|
||||
export default debounce;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user