From 3f298fdb966d7689bd3f4c3196ec9b5602535296 Mon Sep 17 00:00:00 2001 From: Phillip Johnsen Date: Wed, 7 Jan 2015 19:36:32 +0100 Subject: [PATCH 1/2] Refactor Writer.renderTokens() for better readability. Split the old Writer.renderTokens() into several small functions with a single responsible. --- mustache.js | 132 ++++++++++++++++++++++++++++------------------------ 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/mustache.js b/mustache.js index c7ffbef..ab2711b 100644 --- a/mustache.js +++ b/mustache.js @@ -444,84 +444,96 @@ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) { var buffer = ''; - // This function is used to render an arbitrary template - // in the current context by higher-order sections. - var self = this; - function subRender(template) { - return self.render(template, context, partials); - } - - var token, value; + var token, tokenRenderer; for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { token = tokens[i]; + tokenRenderer = this._getTokenRenderer(token[0]); - switch (token[0]) { - case '#': - value = context.lookup(token[1]); + if (tokenRenderer) + buffer += tokenRenderer.call(this, token, context, partials, originalTemplate); + } - if (!value) - continue; + return buffer; + }; - if (isArray(value)) { - for (var j = 0, valueLength = value.length; j < valueLength; ++j) { - buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); - } - } else if (typeof value === 'object' || typeof value === 'string') { - buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); - } else if (isFunction(value)) { - if (typeof originalTemplate !== 'string') - throw new Error('Cannot use higher-order sections without the original template'); + Writer.prototype._getTokenRenderer = function(tokenSymbol) { + return { + '#': this._renderSection, + '^': this._renderInverted, + '>': this._renderPartial, + '&': this._unescapedValue, + 'name': this._escapedValue, + 'text': this._rawValue + }[tokenSymbol]; + }; - // Extract the portion of the original template that the section contains. - value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); + Writer.prototype._renderSection = function (token, context, partials, originalTemplate) { + var self = this; + var buffer = ''; + var value = context.lookup(token[1]); - if (value != null) - buffer += value; - } else { - buffer += this.renderTokens(token[4], context, partials, originalTemplate); - } + // This function is used to render an arbitrary template + // in the current context by higher-order sections. + function subRender(template) { + return self.render(template, context, partials); + } - break; - case '^': - value = context.lookup(token[1]); + if (!value) + return ''; - // Use JavaScript's definition of falsy. Include empty arrays. - // See https://github.com/janl/mustache.js/issues/186 - if (!value || (isArray(value) && value.length === 0)) - buffer += this.renderTokens(token[4], context, partials, originalTemplate); + if (isArray(value)) { + for (var j = 0, valueLength = value.length; j < valueLength; ++j) { + buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate); + } + } else if (typeof value === 'object' || typeof value === 'string') { + buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate); + } else if (isFunction(value)) { + if (typeof originalTemplate !== 'string') + throw new Error('Cannot use higher-order sections without the original template'); - break; - case '>': - if (!partials) - continue; + // Extract the portion of the original template that the section contains. + value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender); - value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; + if (value != null) + buffer += value; + } else { + buffer += this.renderTokens(token[4], context, partials, originalTemplate); + } - if (value != null) - buffer += this.renderTokens(this.parse(value), context, partials, value); + return buffer; + }; - break; - case '&': - value = context.lookup(token[1]); + Writer.prototype._renderInverted = function(token, context, partials, originalTemplate) { + var value = context.lookup(token[1]); - if (value != null) - buffer += value; + // Use JavaScript's definition of falsy. Include empty arrays. + // See https://github.com/janl/mustache.js/issues/186 + if (!value || (isArray(value) && value.length === 0)) + return this.renderTokens(token[4], context, partials, originalTemplate); - break; - case 'name': - value = context.lookup(token[1]); + return ''; + }; - if (value != null) - buffer += mustache.escape(value); + Writer.prototype._renderPartial = function(token, context, partials, originalTemplate) { + if (!partials) + return ''; - break; - case 'text': - buffer += token[1]; - break; - } - } + var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; + return (value != null) ? this.renderTokens(this.parse(value), context, partials, value) : ''; + }; - return buffer; + Writer.prototype._unescapedValue = function(token, context) { + var value = context.lookup(token[1]); + return (value != null) ? value : ''; + }; + + Writer.prototype._escapedValue = function(token, context) { + var value = context.lookup(token[1]); + return (value != null) ? mustache.escape(value) : ''; + }; + + Writer.prototype._rawValue = function(token) { + return token[1]; }; mustache.name = "mustache.js"; From deaf0ba982da275d0756daefd046203c6eeae433 Mon Sep 17 00:00:00 2001 From: Phillip Johnsen Date: Mon, 12 Jan 2015 22:16:35 +0100 Subject: [PATCH 2/2] if-else instead seems to fix perf problems --- mustache.js | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/mustache.js b/mustache.js index ab2711b..1e4d3cd 100644 --- a/mustache.js +++ b/mustache.js @@ -444,29 +444,26 @@ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) { var buffer = ''; - var token, tokenRenderer; + var token, symbol, value; for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) { + value = undefined; token = tokens[i]; - tokenRenderer = this._getTokenRenderer(token[0]); + symbol = token[0]; - if (tokenRenderer) - buffer += tokenRenderer.call(this, token, context, partials, originalTemplate); + if (symbol === '#') value = this._renderSection(token, context, partials, originalTemplate); + else if (symbol === '^') value = this._renderInverted(token, context, partials, originalTemplate); + else if (symbol === '>') value = this._renderPartial(token, context, partials, originalTemplate); + else if (symbol === '&') value = this._unescapedValue(token, context); + else if (symbol === 'name') value = this._escapedValue(token, context); + else if (symbol === 'text') value = this._rawValue(token); + + if (value !== undefined) + buffer += value; } return buffer; }; - Writer.prototype._getTokenRenderer = function(tokenSymbol) { - return { - '#': this._renderSection, - '^': this._renderInverted, - '>': this._renderPartial, - '&': this._unescapedValue, - 'name': this._escapedValue, - 'text': this._rawValue - }[tokenSymbol]; - }; - Writer.prototype._renderSection = function (token, context, partials, originalTemplate) { var self = this; var buffer = ''; @@ -478,8 +475,7 @@ return self.render(template, context, partials); } - if (!value) - return ''; + if (!value) return; if (isArray(value)) { for (var j = 0, valueLength = value.length; j < valueLength; ++j) { @@ -499,7 +495,6 @@ } else { buffer += this.renderTokens(token[4], context, partials, originalTemplate); } - return buffer; }; @@ -510,26 +505,26 @@ // See https://github.com/janl/mustache.js/issues/186 if (!value || (isArray(value) && value.length === 0)) return this.renderTokens(token[4], context, partials, originalTemplate); - - return ''; }; Writer.prototype._renderPartial = function(token, context, partials, originalTemplate) { - if (!partials) - return ''; + if (!partials) return; var value = isFunction(partials) ? partials(token[1]) : partials[token[1]]; - return (value != null) ? this.renderTokens(this.parse(value), context, partials, value) : ''; + if (value != null) + return this.renderTokens(this.parse(value), context, partials, value); }; Writer.prototype._unescapedValue = function(token, context) { var value = context.lookup(token[1]); - return (value != null) ? value : ''; + if (value != null) + return value; }; Writer.prototype._escapedValue = function(token, context) { var value = context.lookup(token[1]); - return (value != null) ? mustache.escape(value) : ''; + if (value != null) + return mustache.escape(value); }; Writer.prototype._rawValue = function(token) {