Interface BatchConstructor<TFn>

Source
Expand description

Options to construct a batch function

A batch function is an async event wrapper that allows multiple calls in an interval to be batched together, and only call the underlying function once.

Optionally, the output can be unbatched to match the inputs.

The API is a lot like debounce, but with an additional batch function and an optional unbatch function.

import { batch } from "@pistonite/pure/sync";

const execute = batch({
fn: (n: number) => {
console.log(n);
},
interval: 100,
// batch receives all the inputs and returns a single input
// here we just sums the inputs
batch: (args: [number][]): [number] => [args.reduce((acc, [n]) => acc + n, 0)],
});

await execute(1); // logs 1 immediately
const p1 = execute(2); // will be resolved at 100ms
const p2 = execute(3); // will be resolved at 100ms
await Promise.all([p1, p2]); // logs 5 after 100ms

The optional unbatch function allows the output to be unbatched, so the promises are resolved as if the underlying function is called directly.

Note that unbatching is usually slow and not required.

import { batch } from "@pistonite/pure/sync";

type Message = {
id: number;
payload: string;
}

const execute = batch({
fn: (messages: Message[]): Message[] => {
console.log(messages.length);
return messages.map((m) => ({
id: m.id,
payload: m.payload + "out",
}));
},
batch: (args: [Message[]][]): [Message[]] => {
const out: Message[] = [];
for (const [messages] of args) {
out.push(...messages);
}
return [out];
},
unbatch: (inputs: [Message[]][], output: Message[]): Message[][] => {
// not efficient, but just for demonstration
const idToOutput = new Map();
for (const o of output) {
idToOutput.set(o.id, o);
}
return inputs.map(([messages]) => {
return messages.map(({id}) => {
return idToOutput.get(m.id)!;
});
});
},
interval: 100,
});

const r1 = await execute([{id: 1, payload: "a"}]); // logs 1 immediately
// r1 is [ {id: 1, payload: "aout"} ]

const p1 = execute([{id: 2, payload: "b"}]); // will be resolved at 100ms
const p2 = execute([{id: 3, payload: "c"}]); // will be resolved at 100ms

const r2 = await p2; // 2 is logged
// r1 is [ {id: 2, payload: "bout"} ]
const r3 = await p3; // nothing is logged, as it's already resolved
// r2 is [ {id: 3, payload: "cout"} ]
interface BatchConstructor<TFn extends AnyFn> {
    batch: (args: Parameters<TFn>[]) => Parameters<TFn>;
    disregardExecutionTime?: boolean;
    fn: TFn;
    interval: number;
    unbatch?: (
        inputs: Parameters<TFn>[],
        output: AwaitRet<TFn>,
    ) => AwaitRet<TFn>[];
}

Properties§

§batch: { ... }

Function to batch the inputs across multiple calls

§disregardExecutionTime?: boolean

See debounce for more information

§fn: TFn

Function to be wrapped

§interval: number

Interval between each batched call

§unbatch?: { ... }

If provided, unbatch the output according to the inputs, so each call receives its own output.

By default, each input will receive the same output from the batched call