flowQueue = ({ name, timeout_ms = 1000 } = {}) => {
let runningResolve = undefined;
let runningReject = undefined;
const q = [];
const ui = htl.html`<code>flowQueue()</code>`;
const run = () => {
const [head, resolve, reject] = q.shift();
let timer;
runningResolve = (val) => {
clearTimeout(timer);
return resolve(val);
};
runningReject = (err) => {
clearTimeout(timer);
return reject(err);
};
timer = setTimeout(
() =>
ui.reject(
new Error(`Timeout (maybe increase timeout_ms?) ${name || ""}`)
),
timeout_ms
);
ui.value = head;
ui.dispatchEvent(new Event("input", { bubbles: true }));
};
ui.send = (task) =>
new Promise((resolve, reject) => {
q.push([task, resolve, reject]);
if (runningResolve === undefined) run();
});
ui.reject = async (err) => {
if (!runningReject) throw new Error(`No task executing! ${name || ""}`);
const resolve = runningResolve;
const reject = runningReject;
runningResolve = undefined;
runningReject = undefined;
reject(err);
if (q.length > 0) run();
};
ui.resolve = async (value) => {
if (!runningResolve) throw new Error(`No task executing! ${name || ""}`);
const resolve = runningResolve;
const reject = runningReject;
runningResolve = undefined;
runningReject = undefined;
if (q.length > 0) run();
try {
value = await value;
resolve(value);
} catch (err) {
reject(err);
}
};
ui.respond = ui.resolve;
return ui;
}