only cache values when it makes sense

pull/769/head
Rich Harris 8 years ago
parent 5636506fc0
commit 531354fc39

@ -125,7 +125,8 @@ export default class Generator {
) { ) {
this.addSourcemapLocations(expression); this.addSourcemapLocations(expression);
const usedContexts: string[] = []; const usedContexts = new Set();
const usedIndexes = new Set();
const { code, helpers } = this; const { code, helpers } = this;
const { contexts, indexes } = block; const { contexts, indexes } = block;
@ -168,12 +169,13 @@ export default class Generator {
); );
} }
if (!~usedContexts.indexOf(name)) usedContexts.push(name); usedContexts.add(name);
} else if (helpers.has(name)) { } else if (helpers.has(name)) {
code.prependRight(node.start, `${self.alias('template')}.helpers.`); code.prependRight(node.start, `${self.alias('template')}.helpers.`);
} else if (indexes.has(name)) { } else if (indexes.has(name)) {
const context = indexes.get(name); const context = indexes.get(name);
if (!~usedContexts.indexOf(context)) usedContexts.push(context); usedContexts.add(context); // TODO is this right?
usedIndexes.add(name);
} else { } else {
// handle shorthand properties // handle shorthand properties
if (parent && parent.type === 'Property' && parent.shorthand) { if (parent && parent.type === 'Property' && parent.shorthand) {
@ -193,7 +195,7 @@ export default class Generator {
code.prependRight(node.start, `state.`); code.prependRight(node.start, `state.`);
} }
if (!~usedContexts.indexOf('state')) usedContexts.push('state'); usedContexts.add('state');
} }
this.skip(); this.skip();
@ -221,6 +223,7 @@ export default class Generator {
return { return {
dependencies: Array.from(dependencies), dependencies: Array.from(dependencies),
contexts: usedContexts, contexts: usedContexts,
indexes: usedIndexes,
snippet: `[✂${expression.start}-${expression.end}✂]`, snippet: `[✂${expression.start}-${expression.end}✂]`,
}; };
} }

@ -12,6 +12,7 @@ export interface BlockOptions {
key?: string; key?: string;
contexts?: Map<string, string>; contexts?: Map<string, string>;
indexes?: Map<string, string>; indexes?: Map<string, string>;
changeableIndexes?: Map<string, boolean>;
contextDependencies?: Map<string, string[]>; contextDependencies?: Map<string, string[]>;
params?: string[]; params?: string[];
indexNames?: Map<string, string>; indexNames?: Map<string, string>;
@ -32,6 +33,7 @@ export default class Block {
contexts: Map<string, string>; contexts: Map<string, string>;
indexes: Map<string, string>; indexes: Map<string, string>;
changeableIndexes: Map<string, boolean>;
contextDependencies: Map<string, string[]>; contextDependencies: Map<string, string[]>;
dependencies: Set<string>; dependencies: Set<string>;
params: string[]; params: string[];
@ -77,6 +79,7 @@ export default class Block {
this.contexts = options.contexts; this.contexts = options.contexts;
this.indexes = options.indexes; this.indexes = options.indexes;
this.changeableIndexes = options.changeableIndexes;
this.contextDependencies = options.contextDependencies; this.contextDependencies = options.contextDependencies;
this.dependencies = new Set(); this.dependencies = new Set();

@ -189,7 +189,10 @@ const preprocessors = {
contexts.set(node.context, context); contexts.set(node.context, context);
const indexes = new Map(block.indexes); const indexes = new Map(block.indexes);
if (node.index) indexes.set(indexName, node.context); if (node.index) indexes.set(node.index, node.context);
const changeableIndexes = new Map(block.changeableIndexes);
if (node.index) changeableIndexes.set(node.index, node.key);
const contextDependencies = new Map(block.contextDependencies); const contextDependencies = new Map(block.contextDependencies);
contextDependencies.set(node.context, dependencies); contextDependencies.set(node.context, dependencies);
@ -203,6 +206,7 @@ const preprocessors = {
contextDependencies, contextDependencies,
contexts, contexts,
indexes, indexes,
changeableIndexes,
listName, listName,
indexName, indexName,
@ -274,6 +278,11 @@ const preprocessors = {
} }
} }
}); });
} else if (attribute.type === 'EventHandler' && attribute.expression) {
attribute.expression.arguments.forEach((arg: Node) => {
const dependencies = block.findDependencies(arg);
block.addDependencies(dependencies);
});
} else if (attribute.type === 'Binding') { } else if (attribute.type === 'Binding') {
const dependencies = block.findDependencies(attribute.value); const dependencies = block.findDependencies(attribute.value);
block.addDependencies(dependencies); block.addDependencies(dependencies);
@ -444,6 +453,7 @@ export default function preprocess(
contexts: new Map(), contexts: new Map(),
indexes: new Map(), indexes: new Map(),
changeableIndexes: new Map(),
contextDependencies: new Map(), contextDependencies: new Map(),
params: ['state'], params: ['state'],

@ -38,8 +38,8 @@ export default function visitWindow(
let usesState = false; let usesState = false;
attribute.expression.arguments.forEach((arg: Node) => { attribute.expression.arguments.forEach((arg: Node) => {
const { contexts } = block.contextualise(arg, null, true); const { dependencies } = block.contextualise(arg, null, true);
if (contexts.length) usesState = true; if (dependencies.length) usesState = true;
}); });
const flattened = flattenReference(attribute.expression.callee); const flattened = flattenReference(attribute.expression.callee);

@ -10,9 +10,15 @@ export default function visitMustacheTag(
state: State, state: State,
node: Node node: Node
) { ) {
const { dependencies, snippet } = block.contextualise(node.expression); const { dependencies, indexes, snippet } = block.contextualise(node.expression);
const shouldCache = node.expression.type !== 'Identifier' || block.contexts.has(node.expression.name); const hasChangeableIndex = Array.from(indexes).some(index => block.changeableIndexes.get(index));
const shouldCache = (
node.expression.type !== 'Identifier' ||
block.contexts.has(node.expression.name) ||
hasChangeableIndex
);
const name = node._state.name; const name = node._state.name;
const value = shouldCache && block.getUniqueName(`${name}_value`); const value = shouldCache && block.getUniqueName(`${name}_value`);
@ -30,14 +36,16 @@ export default function visitMustacheTag(
true true
); );
if (dependencies.length) { if (dependencies.length || hasChangeableIndex) {
const changedCheck = ( const changedCheck = (
( block.hasOutroMethod ? `#outroing || ` : '' ) + ( block.hasOutroMethod ? `#outroing || ` : '' ) +
dependencies.map(dependency => `'${dependency}' in changed`).join(' || ') dependencies.map(dependency => `'${dependency}' in changed`).join(' || ')
); );
const updateCachedValue = `${value} !== ( ${value} = ${snippet} )`;
const condition = shouldCache ? const condition = shouldCache ?
`( ${changedCheck} ) && ${value} !== ( ${value} = ${snippet} )` : ( dependencies.length ? `( ${changedCheck} ) && ${updateCachedValue}` : updateCachedValue ) :
changedCheck; changedCheck;
block.builders.update.addConditionalLine( block.builders.update.addConditionalLine(

@ -26,10 +26,10 @@ export default class CodeBuilder {
this.result += `\n\t${line}`; this.result += `\n\t${line}`;
} else { } else {
if (this.lastCondition) { if (this.lastCondition) {
this.result += `\n}\n\n`; this.result += `\n}`;
} }
this.result += `if ( ${condition} ) {\n\t${line}`; this.result += `${this.last === ChunkType.Block ? '\n\n' : '\n'}if ( ${condition} ) {\n\t${line}`;
this.lastCondition = condition; this.lastCondition = condition;
} }

@ -6,7 +6,10 @@ export default {
] ]
}, },
html: '<p>implement keyed each blocks</p><p>implement client-side hydration</p>', html: `
<p>1: implement keyed each blocks</p>
<p>2: implement client-side hydration</p>
`,
test ( assert, component, target ) { test ( assert, component, target ) {
const [ p1, p2 ] = target.querySelectorAll( 'p' ); const [ p1, p2 ] = target.querySelectorAll( 'p' );
@ -16,7 +19,7 @@ export default {
{ id: 234, description: 'implement client-side hydration' } { id: 234, description: 'implement client-side hydration' }
] ]
}); });
assert.htmlEqual( target.innerHTML, '<p>implement client-side hydration</p>' ); assert.htmlEqual( target.innerHTML, '<p>1: implement client-side hydration</p>' );
const [ p3 ] = target.querySelectorAll( 'p' ); const [ p3 ] = target.querySelectorAll( 'p' );

@ -1,3 +1,3 @@
{{#each todos as todo @id}} {{#each todos as todo, i @id}}
<p>{{todo.description}}</p> <p>{{i+1}}: {{todo.description}}</p>
{{/each}} {{/each}}

Loading…
Cancel
Save