1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-18 09:35:20 +02:00
joplin/packages/lib/AsyncActionQueue.ts

118 lines
3.0 KiB
TypeScript

import shim from './shim';
export interface QueueItemAction {
(): void;
}
export interface QueueItem {
action: QueueItemAction;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
context: any;
}
export enum IntervalType {
Debounce = 1,
Fixed = 2,
}
// The AsyncActionQueue can be used to debounce asynchronous actions, to make sure
// they run in the right order, and also to ensure that if multiple actions are emitted
// only the last one is executed. This is particularly useful to save data in the background.
// Each queue should be associated with a specific entity (a note, resource, etc.)
export default class AsyncActionQueue {
private queue_: QueueItem[] = [];
private interval_: number;
private intervalType_: number;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
private scheduleProcessingIID_: any = null;
private processing_ = false;
private processingFinishedPromise_: Promise<void>;
private onProcessingFinished_: ()=> void;
public constructor(interval = 100, intervalType: IntervalType = IntervalType.Debounce) {
this.interval_ = interval;
this.intervalType_ = intervalType;
this.resetFinishProcessingPromise_();
}
private resetFinishProcessingPromise_() {
this.processingFinishedPromise_ = new Promise<void>(resolve => {
this.onProcessingFinished_ = resolve;
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
public push(action: QueueItemAction, context: any = null) {
this.queue_.push({
action: action,
context: context,
});
this.scheduleProcessing();
}
public get isEmpty(): boolean {
return !this.queue_.length;
}
private scheduleProcessing(interval: number = null) {
if (interval === null) interval = this.interval_;
if (this.scheduleProcessingIID_) {
if (this.intervalType_ === IntervalType.Fixed) return;
shim.clearTimeout(this.scheduleProcessingIID_);
}
this.scheduleProcessingIID_ = shim.setTimeout(() => {
this.scheduleProcessingIID_ = null;
void this.processQueue();
}, interval);
}
private async processQueue() {
if (this.processing_) {
this.scheduleProcessing();
return;
}
this.processing_ = true;
const itemCount = this.queue_.length;
if (itemCount) {
const item = this.queue_[itemCount - 1];
await item.action();
this.queue_.splice(0, itemCount);
}
this.processing_ = false;
if (this.queue_.length === 0) {
this.onProcessingFinished_();
this.resetFinishProcessingPromise_();
}
}
public async reset() {
if (this.scheduleProcessingIID_) {
shim.clearTimeout(this.scheduleProcessingIID_);
this.scheduleProcessingIID_ = null;
}
this.queue_ = [];
return this.processAllNow();
}
public async processAllNow() {
this.scheduleProcessing(1);
return this.waitForAllDone();
}
public async waitForAllDone() {
if (!this.queue_.length) return Promise.resolve();
return this.processingFinishedPromise_;
}
}