mirror of
https://github.com/sveltejs/svelte.git
synced 2024-12-01 17:30:59 +01:00
optimize generated code for if statements
Instead of walking elseif statements recursively, collect all the conditions and blocks into a single if block
This commit is contained in:
parent
fd9dc9033a
commit
64f8e77999
@ -1,23 +0,0 @@
|
||||
import counter from '../utils/counter.js';
|
||||
|
||||
export default {
|
||||
enter ( generator ) {
|
||||
const name = generator.current.name.replace( 'If', 'Else' );
|
||||
|
||||
generator.push({
|
||||
name,
|
||||
localElementDepth: 0,
|
||||
|
||||
initStatements: [],
|
||||
updateStatements: [],
|
||||
teardownStatements: [],
|
||||
|
||||
counter: counter()
|
||||
});
|
||||
},
|
||||
|
||||
leave ( generator ) {
|
||||
generator.addRenderer( generator.current );
|
||||
generator.pop();
|
||||
}
|
||||
};
|
@ -1,125 +1,99 @@
|
||||
import deindent from '../utils/deindent.js';
|
||||
import counter from '../utils/counter.js';
|
||||
|
||||
// collect all the conditions and blocks in the if/elseif/else chain
|
||||
function generateBlock ( generator, node, name ) {
|
||||
// walk the children here
|
||||
generator.push({
|
||||
useAnchor: true,
|
||||
name,
|
||||
target: 'target',
|
||||
localElementDepth: 0,
|
||||
|
||||
initStatements: [],
|
||||
updateStatements: [],
|
||||
teardownStatements: [],
|
||||
|
||||
counter: counter()
|
||||
});
|
||||
node.children.forEach( generator.visit );
|
||||
//generator.visit( node.children );
|
||||
generator.addRenderer( generator.current );
|
||||
generator.pop();
|
||||
// unset the children, to avoid them being visited again
|
||||
node.children = [];
|
||||
}
|
||||
function getConditionsAndBlocks ( generator, node, _name, i = 0 ) {
|
||||
generator.addSourcemapLocations( node.expression );
|
||||
const name = `${_name}_${i}`;
|
||||
|
||||
const conditionsAndBlocks = [{
|
||||
condition: generator.contextualise( node.expression ).snippet,
|
||||
block: name
|
||||
}];
|
||||
generateBlock( generator, node, name );
|
||||
|
||||
if ( node.else && node.else.children.length === 1 &&
|
||||
node.else.children[0].type === 'IfBlock' ) {
|
||||
conditionsAndBlocks.push(
|
||||
...getConditionsAndBlocks( generator, node.else.children[0], _name, i + 1 ) );
|
||||
} else {
|
||||
const name = `${_name}_${i + 1}`;
|
||||
conditionsAndBlocks.push({
|
||||
condition: null,
|
||||
block: node.else ? name : null,
|
||||
});
|
||||
if (node.else) {
|
||||
generateBlock( generator, node.else, name );
|
||||
}
|
||||
}
|
||||
return conditionsAndBlocks;
|
||||
}
|
||||
|
||||
export default {
|
||||
enter ( generator, node ) {
|
||||
const i = generator.counters.if++;
|
||||
|
||||
const { params, target } = generator.current;
|
||||
const name = `ifBlock_${i}`;
|
||||
const renderer = `renderIfBlock_${i}`;
|
||||
const getBlock = `getBlock_${i}`;
|
||||
const currentBlock = `currentBlock_${i}`;
|
||||
|
||||
const elseName = `elseBlock_${i}`;
|
||||
const elseRenderer = `renderElseBlock_${i}`;
|
||||
|
||||
generator.addSourcemapLocations( node.expression );
|
||||
const { snippet } = generator.contextualise( node.expression );
|
||||
const conditionsAndBlocks = getConditionsAndBlocks( generator, node, `renderIfBlock_${i}` );
|
||||
|
||||
generator.current.initStatements.push( deindent`
|
||||
var ${name}_anchor = document.createComment( ${JSON.stringify( `#if ${generator.source.slice( node.expression.start, node.expression.end )}` )} );
|
||||
${generator.appendToTarget( `${name}_anchor` )};
|
||||
|
||||
function ${getBlock} ( ${params} ) {
|
||||
${conditionsAndBlocks.map( ({ condition, block }) => {
|
||||
return `${condition ? `if ( ${condition} ) ` : ''}return ${block};`;
|
||||
} ).join( '\n' )}
|
||||
}
|
||||
|
||||
var ${currentBlock} = ${getBlock}( ${params} );
|
||||
var ${name} = ${currentBlock} && ${currentBlock}( ${params}, component, ${target}, ${name}_anchor );
|
||||
` );
|
||||
|
||||
if ( node.else ) {
|
||||
generator.current.initStatements.push( deindent`
|
||||
var ${name} = null;
|
||||
var ${elseName} = null;
|
||||
|
||||
if ( ${snippet} ) {
|
||||
${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
|
||||
} else {
|
||||
${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
|
||||
}
|
||||
` );
|
||||
} else {
|
||||
generator.current.initStatements.push( deindent`
|
||||
var ${name} = ${snippet} ? ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor ) : null;
|
||||
` );
|
||||
}
|
||||
|
||||
const ifTrue = [ deindent`
|
||||
if ( !${name } ) {
|
||||
${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
|
||||
generator.current.updateStatements.push( deindent`
|
||||
var _${currentBlock} = ${currentBlock};
|
||||
${currentBlock} = ${getBlock}( ${params} );
|
||||
if ( _${currentBlock} === ${currentBlock} && ${name}) {
|
||||
${name}.update( changed, ${params} );
|
||||
} else {
|
||||
${name}.update( changed, ${generator.current.params} );
|
||||
if ( ${name} ) ${name}.teardown( true );
|
||||
${name} = ${currentBlock} && ${currentBlock}( ${params}, component, ${target}, ${name}_anchor );
|
||||
}
|
||||
` ];
|
||||
|
||||
if ( node.else ) {
|
||||
ifTrue.push( deindent`
|
||||
if ( ${elseName } ) {
|
||||
${elseName}.teardown( true );
|
||||
${elseName} = null;
|
||||
}
|
||||
` );
|
||||
}
|
||||
|
||||
const ifFalse = [ deindent`
|
||||
if ( ${name} ) {
|
||||
${name}.teardown( true );
|
||||
${name} = null;
|
||||
}
|
||||
` ];
|
||||
|
||||
if ( node.else ) {
|
||||
ifFalse.push( deindent`
|
||||
if ( !${elseName } ) {
|
||||
${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
|
||||
} else {
|
||||
${elseName}.update( changed, ${generator.current.params} );
|
||||
}
|
||||
` );
|
||||
}
|
||||
|
||||
let update = deindent`
|
||||
if ( ${snippet} ) {
|
||||
${ifTrue.join( '\n\n' )}
|
||||
}
|
||||
|
||||
else {
|
||||
${ifFalse.join( '\n\n' )}
|
||||
}
|
||||
`;
|
||||
|
||||
if ( node.else ) {
|
||||
update += `\nif ( ${elseName} ) ${elseName}.update( changed, ${generator.current.params} );`;
|
||||
}
|
||||
|
||||
generator.current.updateStatements.push( update );
|
||||
` );
|
||||
|
||||
const teardownStatements = [
|
||||
`if ( ${name} ) ${name}.teardown( detach );`
|
||||
];
|
||||
|
||||
if ( node.else ) {
|
||||
teardownStatements.push( `if ( ${elseName} ) ${elseName}.teardown( detach );` );
|
||||
}
|
||||
|
||||
if ( generator.current.localElementDepth === 0 ) {
|
||||
teardownStatements.push( `if ( detach ) ${name}_anchor.parentNode.removeChild( ${name}_anchor );` );
|
||||
}
|
||||
|
||||
generator.current.teardownStatements.push( teardownStatements.join( '\n' ) );
|
||||
|
||||
generator.push({
|
||||
useAnchor: true,
|
||||
name: renderer,
|
||||
target: 'target',
|
||||
localElementDepth: 0,
|
||||
|
||||
initStatements: [],
|
||||
updateStatements: [],
|
||||
teardownStatements: [],
|
||||
|
||||
counter: counter()
|
||||
});
|
||||
},
|
||||
|
||||
leave ( generator, node ) {
|
||||
generator.addRenderer( generator.current );
|
||||
|
||||
if ( node.else ) {
|
||||
generator.visit( node.else );
|
||||
}
|
||||
|
||||
generator.pop();
|
||||
}
|
||||
};
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Comment from './Comment.js';
|
||||
import EachBlock from './EachBlock.js';
|
||||
import Element from './Element.js';
|
||||
import ElseBlock from './ElseBlock.js';
|
||||
import IfBlock from './IfBlock.js';
|
||||
import MustacheTag from './MustacheTag.js';
|
||||
import Text from './Text.js';
|
||||
@ -10,7 +9,6 @@ export default {
|
||||
Comment,
|
||||
EachBlock,
|
||||
Element,
|
||||
ElseBlock,
|
||||
IfBlock,
|
||||
MustacheTag,
|
||||
Text
|
||||
|
Loading…
Reference in New Issue
Block a user