Skip to content

Commit d6311b5

Browse files
authored
fix stale display (#997)
1 parent 69eed90 commit d6311b5

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

src/client/main.js

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,52 @@ export function define(cell) {
2626
cellsById.get(id)?.variables.forEach((v) => v.delete());
2727
cellsById.set(id, {cell, variables});
2828
const root = document.querySelector(`#cell-${id}`);
29-
let reset = null;
30-
const clear = () => ((root.innerHTML = ""), root.classList.remove("observablehq--loading"), (reset = null));
31-
const display = inline
32-
? (v) => {
33-
reset?.();
34-
if (isNode(v) || typeof v === "string" || !v?.[Symbol.iterator]) root.append(v);
35-
else root.append(...v);
36-
return v;
37-
}
38-
: (v) => {
39-
reset?.();
40-
root.append(isNode(v) ? v : inspect(v));
41-
return v;
42-
};
43-
const v = main.variable(
44-
{
45-
_node: root, // for visibility promise
46-
pending: () => (reset = clear),
47-
fulfilled: () => reset?.(),
48-
rejected: (error) => (reset?.(), console.error(error), root.append(inspectError(error)))
49-
},
50-
{
51-
shadow: {
52-
display: () => display,
53-
view: () => (v) => Generators.input(display(v))
29+
const rejected = (error) => (clear(root), console.error(error), root.append(inspectError(error)));
30+
const v = main.variable({_node: root, rejected}, {shadow: {}}); // _node for visibility promise
31+
if (inputs.includes("display") || inputs.includes("view")) {
32+
let displayVersion = -1; // the variable._version of currently-displayed values
33+
const display = inline ? displayInline : displayBlock;
34+
const vd = new v.constructor(2, v._module);
35+
vd.define(
36+
inputs.filter((i) => i !== "display" && i !== "view"),
37+
() => {
38+
let version = v._version; // capture version on input change
39+
return (value) => {
40+
if (version < displayVersion) throw new Error("stale display");
41+
else if (version > displayVersion) clear(root);
42+
displayVersion = version;
43+
display(root, value);
44+
return value;
45+
};
5446
}
47+
);
48+
v._shadow.set("display", vd);
49+
if (inputs.includes("view")) {
50+
const vv = new v.constructor(2, v._module, null, {shadow: {}});
51+
vv._shadow.set("display", vd);
52+
vv.define(["display"], (display) => (v) => Generators.input(display(v)));
53+
v._shadow.set("view", vv);
5554
}
56-
);
55+
}
5756
v.define(outputs.length ? `cell ${id}` : null, inputs, body);
5857
variables.push(v);
5958
for (const o of outputs) variables.push(main.variable(true).define(o, [`cell ${id}`], (exports) => exports[o]));
6059
}
6160

61+
function clear(root) {
62+
root.innerHTML = "";
63+
root.classList.remove("observablehq--loading");
64+
}
65+
66+
function displayInline(root, value) {
67+
if (isNode(value) || typeof value === "string" || !value?.[Symbol.iterator]) root.append(value);
68+
else root.append(...value);
69+
}
70+
71+
function displayBlock(root, value) {
72+
root.append(isNode(value) ? value : inspect(value));
73+
}
74+
6275
export function undefine(id) {
6376
cellsById.get(id)?.variables.forEach((v) => v.delete());
6477
cellsById.delete(id);

0 commit comments

Comments
 (0)