Skip to content

Commit

Permalink
Renderer class
Browse files Browse the repository at this point in the history
  • Loading branch information
overlookmotel committed Jan 21, 2019
1 parent 12b47a7 commit 7168492
Showing 1 changed file with 69 additions and 68 deletions.
137 changes: 69 additions & 68 deletions lib/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,83 +11,84 @@ const PartialRenderer = require('./renderer'),
{isPromise} = require('./utils');

// Exports
module.exports = function render(element, makeStaticMarkup) {
return renderAsync(element, makeStaticMarkup, false, null);
};
class Renderer {
constructor(makeStaticMarkup) {
this.makeStaticMarkup = makeStaticMarkup;
}

function renderAsync(element, makeStaticMarkup, insideSuspense, stackState) {
return new Promise((resolve, reject) => {
const renderer = new PartialRenderer(element, makeStaticMarkup, stackState);
try {
// Render element to HTML
let h = renderer.read(Infinity);
renderAsync(element, insideSuspense, stackState) {
return new Promise((resolve, reject) => {
const renderer = new PartialRenderer(element, this.makeStaticMarkup, stackState);
try {
// Render element to HTML
let h = renderer.read(Infinity);

// If no interrupts, return full HTML
const interrupts = renderer._interrupts;
if (interrupts.length === 0) return resolve(h);
// If no interrupts, return full HTML
const interrupts = renderer._interrupts;
if (interrupts.length === 0) return resolve(h);

// Render was interrupted by Suspense or thrown promise.
// Split HTML into parts around interrupt placeholders
const parts = [];
h.split(PLACEHOLDER).forEach(part => parts.push(part, ''));
parts.length--;
// Render was interrupted by Suspense or thrown promise.
// Split HTML into parts around interrupt placeholders
const parts = [];
h.split(PLACEHOLDER).forEach(part => parts.push(part, ''));
parts.length--;

// Resolve all interrupts and put resulting HTML into parts array
resolveInterrupts(interrupts, parts, makeStaticMarkup, insideSuspense)
.then(() => resolve(parts.join('')))
.catch(reject);
} finally {
renderer.destroy();
}
});
}
// Resolve all interrupts and put resulting HTML into parts array
this.resolveInterrupts(interrupts, parts, insideSuspense)
.then(() => resolve(parts.join('')))
.catch(reject);
} finally {
renderer.destroy();
}
});
}

const resolvers = {
[INTERRUPT_SUSPENSE]: resolveSuspense,
[INTERRUPT_PROMISE]: resolvePromise
};
resolveInterrupts(interrupts, parts, insideSuspense) {
return Promise.all(interrupts.map((interrupt, index) => {
const resolveName = interrupt.type === INTERRUPT_SUSPENSE ? 'resolveSuspense' :
interrupt.type === INTERRUPT_PROMISE ? 'resolvePromise' : null;

function resolveInterrupts(interrupts, parts, makeStaticMarkup, insideSuspense) {
return Promise.all(interrupts.map((interrupt, index) => {
const resolve = resolvers[interrupt.type];
if (!resolve) throw new Error(`Unknown interrupt type '${interrupt.type}'`);
if (!resolveName) throw new Error(`Unknown interrupt type '${interrupt.type}'`);

return resolve(interrupt, makeStaticMarkup, insideSuspense)
.then(part => parts[index * 2 + 1] = part);
}));
}

function resolveSuspense(interrupt, makeStaticMarkup, insideSuspense) {
const {props} = interrupt.element;
return renderAsync(
props.children,
makeStaticMarkup,
true,
interrupt.stackState
).catch(err => {
if (!isPromise(err)) throw err;
return this[resolveName](interrupt, insideSuspense)
.then(part => parts[index * 2 + 1] = part);
}));
}

return renderAsync(
props.fallback,
makeStaticMarkup,
insideSuspense,
resolveSuspense(interrupt, insideSuspense) {
const {props} = interrupt.element;
return this.renderAsync(
props.children,
true,
interrupt.stackState
);
});
}
).catch(err => {
if (!isPromise(err)) throw err;

function resolvePromise(interrupt, makeStaticMarkup, insideSuspense) {
// If fatal interrupt, throw promise
const {promise} = interrupt;
if (!insideSuspense || promise._fatal) throw promise;
return this.renderAsync(
props.fallback,
insideSuspense,
interrupt.stackState
);
});
}

// Resolve promise, then render child again
return promise.then(() => {
return renderAsync(
interrupt.element,
makeStaticMarkup,
true,
interrupt.stackState
);
});
resolvePromise(interrupt, insideSuspense) {
// If fatal interrupt, throw promise
const {promise} = interrupt;
if (!insideSuspense || promise._fatal) throw promise;

// Resolve promise, then render child again
return promise.then(() => {
return this.renderAsync(
interrupt.element,
true,
interrupt.stackState
);
});
}
}

module.exports = function render(element, makeStaticMarkup) {
const renderer = new Renderer(makeStaticMarkup);
return renderer.renderAsync(element, false, null);
};

0 comments on commit 7168492

Please sign in to comment.