Skip to content

Instantly share code, notes, and snippets.

@ifraixedes
Last active August 29, 2015 14:15
Show Gist options
  • Save ifraixedes/d9af03a3b67a8aba4a5c to your computer and use it in GitHub Desktop.
Save ifraixedes/d9af03a3b67a8aba4a5c to your computer and use it in GitHub Desktop.
Performance Execution on JS Objects Created in Different Ways
// 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)');
});
/* 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