-
-
Save saabi/2653077 to your computer and use it in GitHub Desktop.
self = | |
{ | |
header: "Header", | |
header2: "Header2", | |
header3: "Header3", | |
header4: "Header4", | |
header5: "Header5", | |
header6: "Header6", | |
list: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'] | |
}; | |
attrs = function (obj, escaped) { | |
var buf = [] | |
, terse = obj.terse; | |
delete obj.terse; | |
var keys = Object.keys(obj) | |
, len = keys.length; | |
if (len) { | |
buf.push(''); | |
for (var i = 0; i < len; ++i) { | |
var key = keys[i] | |
, val = obj[key]; | |
if ('boolean' == typeof val || null == val) { | |
if (val) { | |
terse | |
? buf.push(key) | |
: buf.push(key + '="' + key + '"'); | |
} | |
} else if (0 == key.indexOf('data') && 'string' != typeof val) { | |
buf.push(key + "='" + JSON.stringify(val) + "'"); | |
} else if ('class' == key && Array.isArray(val)) { | |
buf.push(key + '="' + exports.escape(val.join(' ')) + '"'); | |
} else if (escaped[key]) { | |
buf.push(key + '="' + exports.escape(val) + '"'); | |
} else { | |
buf.push(key + '="' + val + '"'); | |
} | |
} | |
} | |
return buf.join(' '); | |
}; | |
attrs2 = function (obj, escaped) { | |
var terse = obj.terse; | |
delete obj.terse; | |
var keys = Object.keys(obj) | |
, len = keys.length; | |
var s = ' '; | |
if (len) { | |
for (var i = 0; i < len; ++i) { | |
var key = keys[i] | |
, val = obj[key]; | |
if ('boolean' == typeof val || null == val) { | |
if (val) { | |
terse | |
? (s+=key) | |
: (s+=key + '="' + key + '" '); | |
} | |
} else if (0 == key.indexOf('data') && 'string' != typeof val) { | |
s += key + "='" + JSON.stringify(val) + "' "; | |
} else if ('class' == key && Array.isArray(val)) { | |
s += key + '="' + exports.escape(val.join(' ')) + '" '; | |
} else if (escaped[key]) { | |
s += key + '="' + exports.escape(val) + '" '; | |
} else { | |
s += key + '="' + val + '" '; | |
} | |
} | |
} | |
return s; | |
}; | |
jt1 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
var buf = []; | |
//var self = locals || {}; | |
var interp; | |
buf.push('<div><h1'); | |
buf.push(attrs({ "class": ('header') }, {})); | |
buf.push('>'); | |
var __val__ = self.header | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h1><h2'); | |
buf.push(attrs({ "class": ('header2') }, {})); | |
buf.push('>'); | |
var __val__ = self.header2 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h2><h3'); | |
buf.push(attrs({ "class": ('header3') }, {})); | |
buf.push('>'); | |
var __val__ = self.header3 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h3><h4'); | |
buf.push(attrs({ "class": ('header4') }, {})); | |
buf.push('>'); | |
var __val__ = self.header4 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h4><h5'); | |
buf.push(attrs({ "class": ('header5') }, {})); | |
buf.push('>'); | |
var __val__ = self.header5 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h5><h6'); | |
buf.push(attrs({ "class": ('header6') }, {})); | |
buf.push('>'); | |
var __val__ = self.header6 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h6><ul'); | |
buf.push(attrs({ "class": ('list') }, {})); | |
buf.push('>'); | |
// iterate self.list | |
(function() | |
{ | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
buf.push('<li'); | |
buf.push(attrs({ "class": ('item') }, {})); | |
buf.push('>'); | |
var __val__ = item | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</li>'); | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
buf.push('<li'); | |
buf.push(attrs({ "class": ('item') }, {})); | |
buf.push('>'); | |
var __val__ = item | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</li>'); | |
} | |
} | |
} | |
}).call(this); | |
buf.push('</ul></div>');return new Buffer(buf.join("")); | |
} | |
jt2 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
//var self = locals || {}; | |
s ='<div><h1' + attrs2({ "class": ('header') }, {}) + '>'; | |
var __val__ = self.header; | |
s += (null == __val__ ? "" : __val__) + '</h1><h2' + attrs2({ "class": ('header2') }, {}) + '>'; | |
var __val__ = self.header2; | |
s += (null == __val__ ? "" : __val__) + '</h2><h3' + attrs2({ "class": ('header3') }, {}) + '>'; | |
var __val__ = self.header3; | |
s += (null == __val__ ? "" : __val__) + '</h3><h4' + attrs2({ "class": ('header4') }, {}) + '>'; | |
var __val__ = self.header4; | |
s += (null == __val__ ? "" : __val__) + '</h4><h5' + attrs2({ "class": ('header5') }, {}) + '>'; | |
var __val__ = self.header5; | |
s += (null == __val__ ? "" : __val__) + '</h5><h6' + attrs2({ "class": ('header6') }, {}) + '>'; | |
var __val__ = self.header6; | |
s += (null == __val__ ? "" : __val__) + '</h6><ul' + attrs2({ "class": ('list') }, {}) + '>'; | |
// iterate self.list | |
(function() | |
{ | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs2({ "class": ('item') }, {}) + '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__) + '</li>'; | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs2({ "class": ('item') }, {}) + '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__) + '</li>'; | |
} | |
} | |
} | |
}).call(this); | |
s += '</ul></div>'; | |
return new Buffer(s); | |
} | |
jt3 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
//var self = locals || {}; | |
s ='<div><h1' + attrs2({ "class": ('header') }, {}) + '>'; | |
var __val__ = self.header; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h1><h2'; | |
s += attrs2({ "class": ('header2') }, {}); | |
s += '>'; | |
var __val__ = self.header2; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h2><h3'; | |
s += attrs2({ "class": ('header3') }, {}); | |
s += '>'; | |
var __val__ = self.header3; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h3><h4'; | |
s += attrs2({ "class": ('header4') }, {}); | |
s += '>'; | |
var __val__ = self.header4; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h4><h5'; | |
s += attrs2({ "class": ('header5') }, {}); | |
s += '>'; | |
var __val__ = self.header5; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h5><h6'; | |
s += attrs2({ "class": ('header6') }, {}); | |
s += '>'; | |
var __val__ = self.header6; | |
s += (null == __val__ ? "" : __val__); | |
s += '</h6><ul'; | |
s += attrs2({ "class": ('list') }, {}); | |
s += '>'; | |
// iterate self.list | |
(function() | |
{ | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
s += '<li'; | |
s += attrs2({ "class": ('item') }, {}); | |
s += '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__); | |
s += '</li>'; | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
s += '<li'; | |
s += attrs2({ "class": ('item') }, {}); | |
s += '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__); | |
s += '</li>'; | |
} | |
} | |
} | |
}).call(this); | |
s += '</ul></div>'; | |
return new Buffer(s); | |
} | |
jt4 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
//var self = locals || {}; | |
s ='<div><h1' + attrs({ "class": ('header') }, {}) + '>'; | |
var __val__ = self.header; | |
s += (null == __val__ ? "" : __val__) + '</h1><h2' + ({ "class": ('header2') }, {}) + '>'; | |
var __val__ = self.header2; | |
s += (null == __val__ ? "" : __val__) + '</h2><h3' + attrs({ "class": ('header3') }, {}) + '>'; | |
var __val__ = self.header3; | |
s += (null == __val__ ? "" : __val__) + '</h3><h4' + attrs({ "class": ('header4') }, {}) + '>'; | |
var __val__ = self.header4; | |
s += (null == __val__ ? "" : __val__) + '</h4><h5' + attrs({ "class": ('header5') }, {}) + '>'; | |
var __val__ = self.header5; | |
s += (null == __val__ ? "" : __val__) + '</h5><h6' + attrs({ "class": ('header6') }, {}) + '>'; | |
var __val__ = self.header6; | |
s += (null == __val__ ? "" : __val__) + '</h6><ul' + attrs({ "class": ('list') }, {}) + '>'; | |
// iterate self.list | |
(function() | |
{ | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs({ "class": ('item') }, {}) + '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__) + '</li>'; | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs({ "class": ('item') }, {}) + '>'; | |
var __val__ = item; | |
s += (null == __val__ ? "" : __val__) + '</li>'; | |
} | |
} | |
} | |
}).call(this); | |
s += '</ul></div>'; | |
return new Buffer(s); | |
} | |
jt5 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
var buf = []; | |
//var self = locals || {}; | |
var interp; | |
buf.push('<div><h1'); | |
buf.push(attrs2({ "class": ('header') }, {})); | |
buf.push('>'); | |
var __val__ = self.header | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h1><h2'); | |
buf.push(attrs2({ "class": ('header2') }, {})); | |
buf.push('>'); | |
var __val__ = self.header2 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h2><h3'); | |
buf.push(attrs2({ "class": ('header3') }, {})); | |
buf.push('>'); | |
var __val__ = self.header3 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h3><h4'); | |
buf.push(attrs2({ "class": ('header4') }, {})); | |
buf.push('>'); | |
var __val__ = self.header4 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h4><h5'); | |
buf.push(attrs2({ "class": ('header5') }, {})); | |
buf.push('>'); | |
var __val__ = self.header5 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h5><h6'); | |
buf.push(attrs2({ "class": ('header6') }, {})); | |
buf.push('>'); | |
var __val__ = self.header6 | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</h6><ul'); | |
buf.push(attrs2({ "class": ('list') }, {})); | |
buf.push('>'); | |
// iterate self.list | |
(function() | |
{ | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
buf.push('<li'); | |
buf.push(attrs2({ "class": ('item') }, {})); | |
buf.push('>'); | |
var __val__ = item | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</li>'); | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
buf.push('<li'); | |
buf.push(attrs2({ "class": ('item') }, {})); | |
buf.push('>'); | |
var __val__ = item | |
buf.push(null == __val__ ? "" : __val__); | |
buf.push('</li>'); | |
} | |
} | |
} | |
}).call(this); | |
buf.push('</ul></div>');return new Buffer(buf.join("")); | |
} | |
jt6 = function () | |
{ | |
//var attrs = jade.attrs, escape = jade.escape, rethrow = jade.rethrow; | |
//var self = locals || {}; | |
var __val__; | |
s ='<div><h1' + attrs2({ "class": ('header') }, {}) + '>' | |
+ (null == (__val__ = self.header) ? "" : __val__) + '</h1><h2' + ({ "class": ('header2') }, {}) + '>' | |
+ (null == (__val__ = self.header2) ? "" : __val__) + '</h2><h3' + attrs2({ "class": ('header3') }, {}) + '>' | |
+ (null == (__val__ = self.header3) ? "" : __val__) + '</h3><h4' + attrs2({ "class": ('header4') }, {}) + '>' | |
+ (null == (__val__ = self.header4) ? "" : __val__) + '</h4><h5' + attrs2({ "class": ('header5') }, {}) + '>' | |
+ (null == (__val__ = self.header5) ? "" : __val__) + '</h5><h6' + attrs2({ "class": ('header6') }, {}) + '>' | |
+ (null == (__val__ = self.header6) ? "" : __val__) + '</h6><ul' + attrs2({ "class": ('list') }, {}) + '>'; | |
// iterate self.list | |
(function() | |
{ | |
var __val__; | |
if ('number' == typeof self.list.length) | |
{ | |
for (var $index = 0, $$l = self.list.length; $index < $$l; $index++) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs2({ "class": ('item') }, {}) + '>' + (null == (__val__ = item) ? "" : __val__) + '</li>'; | |
} | |
} | |
else | |
{ | |
for (var $index in self.list) | |
{ | |
if (self.list.hasOwnProperty($index)) | |
{ | |
var item = self.list[$index]; | |
s += '<li' + attrs2({ "class": ('item') }, {}) + '>' + (null == (__val__ = item) ? "" : __val__) + '</li>'; | |
} | |
} | |
} | |
}).call(this); | |
s += '</ul></div>'; | |
return new Buffer(s); | |
} | |
var Benchmark = require('benchmark') | |
var suite = new Benchmark.Suite | |
suite | |
.add('jt1 - (b.push())', jt1) | |
.add('jt2 - (+= & +) ', jt2) | |
.add('jt3 - (+= only) ', jt3) | |
.add('jt4 - (+=, +, old attrs) ', jt4) | |
.add('jt5 - (b.push(), attrs2()) ', jt5) | |
.add('jt6 - (mostly +, attrs2()) ', jt6) | |
.on('cycle', function (event, bench) { | |
console.log(bench.toString()); | |
}) | |
.on('complete', function () { | |
console.log('Fastest is ' + this.filter('fastest').pluck('name')) | |
}) | |
.run(); |
You're right. A little bug introduced when modifiying the old attrs() which joins with ' ' at the end.
Fixed by setting var s=' ';
We end up with an extra space at the end, which I'm leaving right now. However, removing it with substr is (edit:probably) faster than the extra concatenations.
Performance results shouldn't change significantly with this modification.
My tests show that substr
is slower. See this.
Good thing I came back to write 'probably' :)
However, do you think it's too sloppy to just leave that extra space at the end? I'll benchmark your attrs
with mine to see if there's a significant difference. If not, then yours is preferable as it leaves cleaner HTML.
I thought that maybe because it possibly used the same character buffer for the new substring it would just be a matter of creating a new String object, hence it would be a fast operation. Maybe it does a copy operation to form the substring, collapsing the internal linked list.
I think you'll need to have correct html that passes all the jade tests.
For your attrs2 code, shouldn't there be a space added to the start (not the end) for each new key/value that gets appended? This requires more concatenations which decreases performance but it is necessary to render right.
Otherwise you get things like
<pclass="something" >
instead of<p class="something">
.