Last active
August 29, 2015 14:15
-
-
Save ifraixedes/d9af03a3b67a8aba4a5c to your computer and use it in GitHub Desktop.
Performance Execution on JS Objects Created in Different Ways
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Requires "npm install benchmark microtime" | |
/* helper functions */ | |
function printSuiteResult(suiteResult, title) { | |
console.log("### " + title + " ###"); | |
suiteResult.forEach(function (btest) { | |
var sep = ""; | |
for (var s = 85 - btest.name.length; s > 0; s--) { | |
sep += " "; | |
} | |
console.log("%s %s mean: %s us / deviation: %s", btest.name, sep, btest.stats.mean * 1000000, btest.stats.deviation); | |
}); | |
console.log('################################'); | |
} | |
/* Usual Constructor Function */ | |
function ContentPrototype() { | |
this.text = null; | |
} | |
ContentPrototype.prototype.set = function (text) { | |
if (typeof text !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
this.text = text; | |
}; | |
ContentPrototype.prototype.get = function (text) { | |
return this.text; | |
}; | |
/* Usual Constructor Function without Object Prototype */ | |
function ContentPrototypeNull() { | |
this.text = null; | |
} | |
ContentPrototypeNull.prototype.__proto__ = null; | |
ContentPrototypeNull.prototype.set = function (text) { | |
if (typeof text !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
this.text = text; | |
}; | |
ContentPrototypeNull.prototype.get = function (text) { | |
return this.text; | |
}; | |
/* Constructor Function which uses `Object.defineProperty` */ | |
function ContentProperty() { | |
var text = null; | |
Object.defineProperty(this, 'content', { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}); | |
} | |
/* Constructor Function which uses `Object.defineProperty` without Object Prototype */ | |
function ContentPropertyNull() { | |
var text = null; | |
Object.defineProperty(this, 'content', { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}); | |
} | |
ContentPropertyNull.prototype.__proto__ = null; | |
/* Function which returns an Usual Object Literal */ | |
function contentFunction() { | |
var text = null; | |
return { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}; | |
} | |
/* Function which returns an Object Literal without Object Prototype */ | |
function contentFunctionNull() { | |
var text = null; | |
var obj = Object.create(null); | |
obj.set = function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}; | |
obj.get = function () { | |
return text; | |
}; | |
return obj; | |
} | |
/* Function which returns an Object created by `Object.create` defining properties */ | |
function contentFunctionObjCreate() { | |
var text = null; | |
return Object.create(Object, { | |
content: { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
} | |
}); | |
} | |
/* Function which returns an Object created by `Object.create` defining properties without Object Prototype */ | |
function contentFunctionObjCreateNull() { | |
var text = null; | |
return Object.create(null, { | |
content: { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
} | |
}); | |
} | |
// Simple implementation test | |
var assert = require('assert'); | |
var cProto = new ContentPrototype(); | |
try { | |
cProto.set({}); | |
console.error('Error expected to assign non string to a ContentPrototype instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProto.set('hey you'); | |
assert.equal(cProto.get(), 'hey you'); | |
var cProtoNull = new ContentPrototypeNull(); | |
try { | |
cProtoNull.set({}); | |
console.error('Error expected to assign non string to a ContentPrototypeNull instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProtoNull.set('hey you'); | |
assert.equal(cProtoNull.get(), 'hey you'); | |
var cProp = new ContentProperty(); | |
try { | |
cProp.content = {}; | |
console.error('Error expected to assign non string to a ContentProperty instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProp.content = 'hey you'; | |
assert.equal(cProp.content, 'hey you'); | |
var cPropNull = new ContentPropertyNull(); | |
try { | |
cPropNull.content = {}; | |
console.error('Error expected to assign non string to a ContentPropertyNull instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cPropNull.content = 'hey you'; | |
assert.equal(cPropNull.content, 'hey you'); | |
var cFunc = contentFunction(); | |
try { | |
cFunc.set({}); | |
console.error('Error expected to assign non string to a contentFunction returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFunc.set('hey you'); | |
assert.equal(cFunc.get(), 'hey you'); | |
var cFuncNull = contentFunctionNull(); | |
try { | |
cFuncNull.set({}); | |
console.error('Error expected to assign non string to a contentFunctionNull returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncNull.set('hey you'); | |
assert.equal(cFuncNull.get(), 'hey you'); | |
var cFuncObjCreate = contentFunctionObjCreate(); | |
try { | |
cFuncObjCreate.content = {}; | |
console.error('Error expected to assign non string to a contentFunctionObjCreate returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncObjCreate.content = 'hey you'; | |
assert.equal(cFuncObjCreate.content, 'hey you'); | |
var cFuncObjCreateNull = contentFunctionObjCreateNull(); | |
try { | |
cFuncObjCreateNull.content = {}; | |
console.error('Error expected to assign non string to a contentFunctionObjCreateNull returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncObjCreateNull.content = 'hey you'; | |
assert.equal(cFuncObjCreateNull.content, 'hey you'); | |
// End implementation simple test | |
var Benchmark = require('benchmark'); | |
var suiteWriteAsync = Benchmark.Suite(); | |
var suiteWriteSync = Benchmark.Suite(); | |
var suiteReadAsync = Benchmark.Suite(); | |
var suiteReadSync = Benchmark.Suite(); | |
suiteWriteAsync.add("Usual Constructor Function", function () { | |
cProto.set('hey you'); | |
}) | |
.add("Usual Constructor Function NO Object Prototype", function () { | |
cProtoNull.set('hey you'); | |
}) | |
.add("Constructor Function using Object.defineProperty", function () { | |
cProp.content = 'hey you'; | |
}) | |
.add("Constructor Function using Object.defineProperty NO Object Prototype", function () { | |
cPropNull.content = 'hey you'; | |
}) | |
.add("Function returns an Object Literal", function () { | |
cFunc.set('hey you'); | |
}) | |
.add("Function returns an Object Literal NO Object Prototype", function () { | |
cFuncNull.set('hey you'); | |
}) | |
.add("Function returns Object.create defining properties", function () { | |
cFuncObjCreate.content = 'hey you'; | |
}) | |
.add("Function returns Object.create defining properties NO Object Prototype", function () { | |
cFuncObjCreateNull.content = 'hey you'; | |
}) | |
.on('complete', function () { | |
printSuiteResult(this, 'Writing value (async)'); | |
suiteWriteSync.run({ async: false }); | |
}) | |
.run({ async: true }); | |
suiteWriteSync.add("Usual Constructor Function", function () { | |
cProto.set('hey you'); | |
}) | |
.add("Usual Constructor Function NO Object Prototype", function () { | |
cProtoNull.set('hey you'); | |
}) | |
.add("Constructor using Object.defineProperty", function () { | |
cProp.content = 'hey you'; | |
}) | |
.add("Constructor Function using Object.defineProperty NO Object Prototype", function () { | |
cPropNull.content = 'hey you'; | |
}) | |
.add("Function returns an Object Literal", function () { | |
cFunc.set('hey you'); | |
}) | |
.add("Function returns an Object Literal NO Object Prototype", function () { | |
cFuncNull.set('hey you'); | |
}) | |
.add("Function returns Object.create defining properties", function () { | |
cFuncObjCreate.content = 'hey you'; | |
}) | |
.add("Function returns Object.create defining properties NO Object Prototype", function () { | |
cFuncObjCreateNull.content = 'hey you'; | |
}) | |
.on('complete', function () { | |
printSuiteResult(this, 'Writing value (sync)'); | |
suiteReadAsync.run({ async: true }); | |
}); | |
suiteReadAsync.add("Usual Constructor Function", function () { | |
cProto.get(); | |
}) | |
.add("Usual Constructor Function NO Object Prototype", function () { | |
cProtoNull.get(); | |
}) | |
.add("Constructor using Object.defineProperty", function () { | |
cProp.content; | |
}) | |
.add("Constructor Function using Object.defineProperty NO Object Prototype", function () { | |
cPropNull.content; | |
}) | |
.add("Function returns an Object Literal", function () { | |
cFunc.get(); | |
}) | |
.add("Function returns an Object Literal NO Object Prototype", function () { | |
cFuncNull.get(); | |
}) | |
.add("Function returns Object.create defining properties", function () { | |
cFuncObjCreate.content; | |
}) | |
.add("Function returns Object.create defining properties NO Object Prototype", function () { | |
cFuncObjCreateNull.content; | |
}) | |
.on('complete', function () { | |
printSuiteResult(this, 'Reading value (async)'); | |
suiteReadSync.run({ async: false }); | |
}); | |
suiteReadSync.add("Usual Constructor Function", function () { | |
cProto.get(); | |
}) | |
.add("Usual Constructor Function NO Object Prototype", function () { | |
cProtoNull.get(); | |
}) | |
.add("Constructor using Object.defineProperty", function () { | |
cProp.content; | |
}) | |
.add("Constructor Function using Object.defineProperty NO Object Prototype", function () { | |
cPropNull.content; | |
}) | |
.add("Function returns an Object Literal", function () { | |
cFunc.get(); | |
}) | |
.add("Function returns an Object Literal NO Object Prototype", function () { | |
cFuncNull.get(); | |
}) | |
.add("Function returns Object.create defining properties", function () { | |
cFuncObjCreate.content; | |
}) | |
.add("Function returns Object.create defining properties NO Object Prototype", function () { | |
cFuncObjCreateNull.content; | |
}) | |
.on('complete', function () { | |
printSuiteResult(this, 'Reading value (sync)'); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* helper functions */ | |
function average(collection) { | |
var total = collection.reduce(function (acc, value) { | |
return acc + value; | |
}, 0); | |
return total/collection.length; | |
} | |
/* Usual Constructor Function */ | |
function ContentPrototype() { | |
this.text = null; | |
} | |
ContentPrototype.prototype.set = function (text) { | |
if (typeof text !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
this.text = text; | |
}; | |
ContentPrototype.prototype.get = function (text) { | |
return this.text; | |
}; | |
/* Usual Constructor Function without Object Prototype */ | |
function ContentPrototypeNull() { | |
this.text = null; | |
} | |
ContentPrototypeNull.prototype.__proto__ = null; | |
ContentPrototypeNull.prototype.set = function (text) { | |
if (typeof text !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
this.text = text; | |
}; | |
ContentPrototypeNull.prototype.get = function (text) { | |
return this.text; | |
}; | |
/* Constructor Function which uses `Object.defineProperty` */ | |
function ContentProperty() { | |
var text = null; | |
Object.defineProperty(this, 'content', { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}); | |
} | |
/* Constructor Function which uses `Object.defineProperty` without Object Prototype */ | |
function ContentPropertyNull() { | |
var text = null; | |
Object.defineProperty(this, 'content', { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}); | |
} | |
ContentPropertyNull.prototype.__proto__ = null; | |
/* Function which returns an Usual Object Literal */ | |
function contentFunction() { | |
var text = null; | |
return { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
}; | |
} | |
/* Function which returns an Object Literal without Object Prototype */ | |
function contentFunctionNull() { | |
var text = null; | |
var obj = Object.create(null); | |
obj.set = function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}; | |
obj.get = function () { | |
return text; | |
}; | |
return obj; | |
} | |
/* Function which returns an Object created by `Object.create` defining properties */ | |
function contentFunctionObjCreate() { | |
var text = null; | |
return Object.create(Object, { | |
content: { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
} | |
}); | |
} | |
/* Function which returns an Object created by `Object.create` defining properties without Object Prototype */ | |
function contentFunctionObjCreateNull() { | |
var text = null; | |
return Object.create(null, { | |
content: { | |
set: function (c) { | |
if (typeof c !== 'string') { | |
throw new Error('Content mus be a string'); | |
} | |
text = c; | |
}, | |
get: function () { | |
return text; | |
} | |
} | |
}); | |
} | |
// Simple implementation test | |
var assert = require('assert'); | |
assert.equal(average([2, 4, 3, 7]), 4); | |
var cProto = new ContentPrototype(); | |
try { | |
cProto.set({}); | |
console.error('Error expected to assign non string to a ContentPrototype instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProto.set('hey you'); | |
assert.equal(cProto.get(), 'hey you'); | |
var cProtoNull = new ContentPrototypeNull(); | |
try { | |
cProtoNull.set({}); | |
console.error('Error expected to assign non string to a ContentPrototypeNull instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProtoNull.set('hey you'); | |
assert.equal(cProtoNull.get(), 'hey you'); | |
var cProp = new ContentProperty(); | |
try { | |
cProp.content = {}; | |
console.error('Error expected to assign non string to a ContentProperty instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cProp.content = 'hey you'; | |
assert.equal(cProp.content, 'hey you'); | |
var cPropNull = new ContentPropertyNull(); | |
try { | |
cPropNull.content = {}; | |
console.error('Error expected to assign non string to a ContentPropertyNull instance'); | |
process.exit(1); | |
} catch (e) { }; | |
cPropNull.content = 'hey you'; | |
assert.equal(cPropNull.content, 'hey you'); | |
var cFunc = contentFunction(); | |
try { | |
cFunc.set({}); | |
console.error('Error expected to assign non string to a contentFunction returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFunc.set('hey you'); | |
assert.equal(cFunc.get(), 'hey you'); | |
var cFuncNull = contentFunctionNull(); | |
try { | |
cFuncNull.set({}); | |
console.error('Error expected to assign non string to a contentFunctionNull returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncNull.set('hey you'); | |
assert.equal(cFuncNull.get(), 'hey you'); | |
var cFuncObjCreate = contentFunctionObjCreate(); | |
try { | |
cFuncObjCreate.content = {}; | |
console.error('Error expected to assign non string to a contentFunctionObjCreate returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncObjCreate.content = 'hey you'; | |
assert.equal(cFuncObjCreate.content, 'hey you'); | |
var cFuncObjCreateNull = contentFunctionObjCreateNull(); | |
try { | |
cFuncObjCreateNull.content = {}; | |
console.error('Error expected to assign non string to a contentFunctionObjCreateNull returned object'); | |
process.exit(1); | |
} catch (e) { }; | |
cFuncObjCreateNull.content = 'hey you'; | |
assert.equal(cFuncObjCreateNull.content, 'hey you'); | |
// End implementation simple test | |
var nti; | |
var it; | |
var WARM_UP = 10; | |
var PERF_TEST_ITERATIONS = 110; | |
var NUM_ITERATIONS = 9999999; | |
var startTime; | |
var results = { | |
protoSet: [], | |
protoGet: [], | |
protoNullSet: [], | |
protoNullGet: [], | |
propSet: [], | |
propGet: [], | |
propNullSet: [], | |
propNullGet: [], | |
funcSet: [], | |
funcGet: [], | |
funcNullSet: [], | |
funcNullGet: [], | |
funcObjCreateSet: [], | |
funcObjCreateGet: [], | |
funcObjCreateNullSet: [], | |
funcObjCreateNullGet: [] | |
}; | |
for (nti = 0; nti < PERF_TEST_ITERATIONS; nti++) { | |
if (nti === WARM_UP) { | |
Object.keys(results).forEach(function (key) { | |
results[key] = []; | |
}); | |
} | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProto.set('hey you'); | |
} | |
results.protoSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProto.get(); | |
} | |
results.protoGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProtoNull.set('hey you'); | |
} | |
results.protoNullSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProtoNull.get(); | |
} | |
results.protoNullGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProp.content = 'hey you'; | |
} | |
results.propSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cProp.content; | |
} | |
results.propGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cPropNull.content = 'hey you'; | |
} | |
results.propNullSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cPropNull.content; | |
} | |
results.propNullGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFunc.set('hey you'); | |
} | |
results.funcSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFunc.get(); | |
} | |
results.funcGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncNull.set('hey you'); | |
} | |
results.funcNullSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncNull.get(); | |
} | |
results.funcNullGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncObjCreate.content = 'hey you'; | |
} | |
results.funcObjCreateSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncObjCreate.content; | |
} | |
results.funcObjCreateGet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncObjCreateNull.content = 'hey you'; | |
} | |
results.funcObjCreateNullSet.push(Date.now() - startTime); | |
startTime = Date.now(); | |
for (it = 0; it < NUM_ITERATIONS; it++) { | |
cFuncObjCreateNull.content; | |
} | |
results.funcObjCreateNullGet.push(Date.now() - startTime); | |
} | |
console.log('### Writting value (average time) ###'); | |
console.log('Usual Constructor Function: %s us', (average(results.protoSet) / NUM_ITERATIONS) * 1000); | |
console.log('Usual Constructor Function NO Object Prototype: %s us', (average(results.protoNullSet) / NUM_ITERATIONS) * 1000); | |
console.log('Constructor Function using Object.defineProperty: %s us', (average(results.propSet) / NUM_ITERATIONS) * 1000); | |
console.log('Constructor Function using Object.defineProperty NO Object Prototype: %s us', (average(results.propNullSet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns an Object Literal: %s us', (average(results.funcSet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns an Object Literal NO Object Prototype: %s us', (average(results.funcNullSet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns Object.create defining properties: %s us', (average(results.funcObjCreateSet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns Object.create defining properties NO Object Prototype: %s us', (average(results.funcObjCreateNullSet) / NUM_ITERATIONS) * 1000); | |
console.log('####################################################################################'); | |
console.log('\n### Reading value (average time) ###'); | |
console.log('Usual Constructor Function: %s us', (average(results.protoGet) / NUM_ITERATIONS) * 1000); | |
console.log('Usual Constructor Function NO Object Prototype: %s us', (average(results.protoNullGet) / NUM_ITERATIONS) * 1000); | |
console.log('Constructor Function using Object.defineProperty: %s us', (average(results.propGet) / NUM_ITERATIONS) * 1000); | |
console.log('Constructor Function using Object.defineProperty NO Object Prototype: %s us', (average(results.propNullGet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns an Object Literal: %s us', (average(results.funcGet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns an Object Literal NO Object Prototype: %s us', (average(results.funcNullGet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns Object.create defining properties: %s us', (average(results.funcObjCreateGet) / NUM_ITERATIONS) * 1000); | |
console.log('Function returns Object.create defining properties NO Object Prototype: %s us', (average(results.funcObjCreateNullGet) / NUM_ITERATIONS) * 1000); | |
console.log('####################################################################################'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment