Skip to content

Commit

Permalink
fix suspense
Browse files Browse the repository at this point in the history
  • Loading branch information
ryansolid committed May 24, 2019
1 parent 6a526b4 commit 8384fe5
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 57 deletions.
36 changes: 28 additions & 8 deletions dom-expressions.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,35 @@ module.exports = {
output: 'test/runtime.js',
variables: {
imports: [ `import {
comp as wrap, sample, root, cleanup, setContext, lookupContext,
getContextOwner as currentContext, makeDataNode
comp as wrap, sample, root, cleanup, getContextOwner as currentContext,
setContext, makeDataNode
} from '@ryansolid/s-js'` ],
SuspenseContext: `{
id: 'suspense', initFn: () => {
const s = makeDataNode(0);
return [s.current.bind(s), s.next.bind(s)];
}
}`,
declarations: {
SuspenseContext: `{
id: 'suspense', initFn: () => {
let counter = 0,
first = true;
const s = makeDataNode(),
increment = () => {
(++counter === 1 && !first) && s.next();
first = false;
},
decrement = () => {
(--counter === 0) && s.next();
},
count = () => {
s.current();
return counter;
}
return {increment, decrement, count};
}
}`,
registerSuspense: `() => {
const c = SuspenseContext.initFn();
setContext(SuspenseContext.id, c);
return c.count;
}`
},
includeContext: true
}
}
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "dom-expressions",
"description": "A Fine-Grained Runtime for Performant DOM Rendering",
"version": "0.9.0-beta.2",
"version": "0.9.0-beta.3",
"author": "Ryan Carniato",
"license": "MIT",
"repository": {
Expand Down
88 changes: 46 additions & 42 deletions template/runtime.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Attributes } from 'dom-expressions';
<%- imports.join(';\n') %>;

<%- (function() {
const decls = ['wrap', 'root', 'sample', 'cleanup', 'setContext', 'currentContext', 'SuspenseContext']
.filter(decl => locals[decl])
.map(decl => `${decl} = ${locals[decl]}`)
if (!locals.declarations) return '';
const decls = Object.keys(declarations)
.map(decl => `${decl} = ${declarations[decl]}`)
return decls.length ? `const ${decls.join(',\n')};` : '';
})();
%>
Expand Down Expand Up @@ -570,55 +570,59 @@ export function each(parent, accessor, expr, options, afterNode) {
}

export function suspend(parent, accessor, expr, options, marker) {
let beforeNode, disposable, current, isSuspended;
let beforeNode, disposable, current, isSuspended, rendered, first = true;
const { fallback } = options,
doc = document.implementation.createHTMLDocument();
<% if(locals.includeContext) { %>
wrap(() => {
if (accessor) {
isSuspended = accessor;
} else {
const c = SuspenseContext.initFn();
isSuspended = c[0];
setContext(SuspenseContext.id, c)
}
insertExpression(parent, sample(expr), null, marker);
});
<% } else { %>
isSuspended = accessor;
insertExpression(parent, sample(expr), null, marker);
<% } %>

if (marker) beforeNode = marker.previousSibling;
for (let name of eventRegistry.keys()) doc.addEventListener(name, eventHandler);
Object.defineProperty(doc.body, 'host', { get() { return (marker && marker.parentNode) || parent; } });
cleanup(function dispose() { disposable && disposable(); });

wrap((cached = false) => {
const value = !!isSuspended();
let node;
if (value === cached) return cached;
parent = (marker && marker.parentNode) || parent;
if (value) {
node = beforeNode ? beforeNode.nextSibling : parent.firstChild;
while (node && node !== marker) {
const next = node.nextSibling;
doc.body.appendChild(node);
node = next;
wrap(() => {
<% if(locals.includeContext) { %>
isSuspended = accessor || registerSuspense();
<% } else { %>
isSuspended = accessor;
<% } %>
rendered = sample(expr);
wrap(cached => {
const value = !!isSuspended();
if (value === cached) return cached;
let node;
parent = (marker && marker.parentNode) || parent;
if (value) {
if (first) {
insertExpression(doc.body, rendered);
first = false;
} else {
node = beforeNode ? beforeNode.nextSibling : parent.firstChild;
while (node && node !== marker) {
const next = node.nextSibling;
doc.body.appendChild(node);
node = next;
}
}
if (fallback) {
sample(() => root(disposer => {
disposable = disposer;
current = insertExpression(parent, fallback(), null, marker)
}));
}
return value;
}
if (fallback) {
sample(() => root(disposer => {
disposable = disposer;
current = insertExpression(parent, fallback(), null, marker);
}));
if (first) {
insertExpression(parent, rendered, null, marker);
first = false;
} else {
if (disposable) {
clearAll(parent, current, marker, beforeNode ? beforeNode.nextSibling : parent.firstChild);
disposable();
}
while (node = doc.body.firstChild) parent.insertBefore(node, marker);
}
return value;
}
if (disposable) {
clearAll(parent, current, marker, beforeNode ? beforeNode.nextSibling : parent.firstChild);
disposable();
}
while (node = doc.body.firstChild) parent.insertBefore(node, marker);
return value;
});
});
}
<% if(locals.includeContext) { %>
Expand Down
10 changes: 5 additions & 5 deletions test/suspend.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,16 +92,16 @@ describe('Testing an only child suspend control flow with DOM children and fallb
describe('Testing a context suspend control flow', () => {
let div, disposer, resolver;
const handlePromise = p => {
const [processing, register] = S.lookupContext('suspense');
const {increment, decrement} = S.lookupContext('suspense');
const s = S.makeDataNode();
register(processing() + 1);
p.then(v => s.next(v)).finally(() => register(processing() - 1));
increment();
p.then(v => s.next(v)).finally(decrement);
return s.current.bind(s);
},
LazyComponent = (props) => {
const getComp = handlePromise(new Promise(resolve => resolver = resolve))
const getComp = handlePromise(new Promise(resolve => resolver = resolve));
let Comp;
return () => (Comp = getComp()) && S.sample(() => Comp(props));
return () => (Comp = getComp()) && (S.sample(() => Comp(props)));
},
ChildComponent = (props) => props.greeting,
Component = () =>
Expand Down

0 comments on commit 8384fe5

Please sign in to comment.