function newReactiveNodeTemplate({
createPlaceholder = () => document.createComment(""),
createNode = toDomNode,
updatePlaceholder = (placeholder, node, prev) => {
if (!placeholder.isConnected) return false;
if (prev) prev.parentElement.removeChild(prev);
if (node) placeholder.parentElement.insertBefore(node, placeholder);
return true;
}
} = {}) {
return (iterator) => {
const placeholder = createPlaceholder();
let stopped = false;
let resolve;
const call = (m) =>
new Promise(async (r) => {
let result;
try {
resolve = r;
result = await m();
} catch (error) {
stopped = true;
}
resolve(result);
resolve = undefined;
});
const stop = () => {
stopped = true;
iterator.return && iterator.return();
resolve && resolve();
};
const start = async () => {
let node;
try {
const next = iterator.next.bind(iterator);
while (!stopped) {
const slot = await call(next);
if (stopped || !slot || slot.done) break;
const value = await call(() => slot.value);
if (stopped) break;
const newNode = createNode(value);
if (newNode !== node) {
if (!updatePlaceholder(placeholder, newNode, node)) {
break;
}
node = newNode;
}
}
} finally {
stop();
}
};
return [placeholder, start, stop];
};
}