export type Resolvers<T = void> = ReturnType<typeof withResolvers<T>>;
export const withResolvers = /* typeof Promise.withResolvers === 'function' ? Promise.withResolvers : */ (<T = void>() => {
let resolve: (val: T) => void;
let reject: (err: unknown) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return {
promise,
resolve: resolve!,
reject: reject!,
};
});
export class OperationBatcher<TEntry, TReturn = void> {
protected readonly pending: Map<TEntry, Resolvers<TReturn>>
protected timer: ReturnType<typeof setTimeout> | null;
constructor(
protected readonly callback: (
batch: [entry: TEntry, resolvers: Resolvers<TReturn>][],
) => unknown,
) {
this.pending = new Map();
this.timer = null;
}
schedule(item: TEntry): Resolvers<TReturn> {
let resolvers = this.pending.get(item);
if (resolvers === undefined) {
resolvers = withResolvers<TReturn>();
this.pending.set(item, resolvers);
}
if (this.timer === null) {
this.timer = setTimeout(() => {
this.timer = null;
if (this.pending.size === 0) {
return;
}
this.callback(Array.from(this.pending.entries()));
this.pending.clear();
}, 0);
}
return resolvers;
}
}
export type Resolvers<T = void> = ReturnType<typeof withResolvers<T>>;
export const withResolvers = /* typeof Promise.withResolvers === 'function' ? Promise.withResolvers : */ (<T = void>() => {
let resolve: (val: T) => void;
let reject: (err: unknown) => void;
const promise = new Promise<T>((res, rej) => {
resolve = res;
reject = rej;
});
return {
promise,
resolve: resolve!,
reject: reject!,
};
});
export class OperationBatcher<TEntry, TReturn = void> {
protected readonly pending: Map<TEntry, Resolvers<TReturn>>
protected timer: ReturnType<typeof setTimeout> | null;
constructor(
protected readonly callback: (
batch: [entry: TEntry, resolvers: Resolvers<TReturn>][],
) => unknown,
) {
this.pending = new Map();
this.timer = null;
}
schedule(item: TEntry): Resolvers<TReturn> {
let resolvers = this.pending.get(item);
if (resolvers === undefined) {
resolvers = withResolvers<TReturn>();
this.pending.set(item, resolvers);
}
if (this.timer === null) {
this.timer = setTimeout(() => {
this.timer = null;
if (this.pending.size === 0) {
return;
}
this.callback(Array.from(this.pending.entries()));
this.pending.clear();
}, 0);
}
return resolvers;
}
}