admin管理员组文章数量:1400424
I wanted to extend String object prototype with some utility method. It worked, but the performance was surprisingly low. Passing a string to a function is 10x times faster than overriding the String.prototype
method that is doing the same thing. To make sure this really happens I created a very simple count()
function and the corresponding methods.
(I was experimenting, and created three different versions of the method.)
function count(str, char) {
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
String.prototype.count = function (char) {
var n = 0;
for (var i = 0; i < this.length; i++) if (this[i] == char) n++;
return n;
}
String.prototype.count_reuse = function (char) {
return count(this, char)
}
String.prototype.count_var = function (char) {
var str = this;
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
// Here is how I measued speed, using Node.js 6.1.0
var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e3//6;
console.time('func')
for (var i = 0; i < REP; i++) count(STR,'1')
console.timeEnd('func')
console.time('proto')
for (var i = 0; i < REP; i++) STR.count('1')
console.timeEnd('proto')
console.time('proto-reuse')
for (var i = 0; i < REP; i++) STR.count_reuse('1')
console.timeEnd('proto-reuse')
console.time('proto-var')
for (var i = 0; i < REP; i++) STR.count_var('1')
console.timeEnd('proto-var')
Results:
func: 705 ms
proto: 10011 ms
proto-reuse: 10366 ms
proto-var: 9703 ms
As you can see the difference is dramatic.
The below proves that performance of method calls is neglectably slower, and that the function code it self is slower for methods.
function count_dummy(str, char) {
return 1234;
}
String.prototype.count_dummy = function (char) {
return 1234; // Just to prove that accessing the method is not the bottle-neck.
}
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
console.time('proto-dummy')
for (var i = 0; i < REP; i++) STR.count_dummy('1')
console.timeEnd('proto-dummy')
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
Results:
func-dummy: 0.165ms
proto-dummy: 0.247ms
Although on huge repetitions (like 1e8) prototyped methods proves to be 10x times slower than functions, this can be ignored for this case.
All this may be related only to a String object, because simple generic objects perform about the same when you pass them to functions or call their methods:
var A = { count: 1234 };
function getCount(obj) { return obj.count }
A.getCount = function() { return this.count }
console.time('func')
for (var i = 0; i < 1e9; i++) getCount(A)
console.timeEnd('func')
console.time('method')
for (var i = 0; i < 1e9; i++) A.getCount()
console.timeEnd('method')
Results:
func: 1689.942ms
method: 1674.639ms
I've been searching on Stackoverflow and binging, but other that the remendation "do not extend String or Array because you pollute the name space" (which is not a problem for my particular project), I cannot find anything related to performance of methods pared to functions. So should I simply forget about extending the String object due to performance drop of added methods or there is more about it?
I wanted to extend String object prototype with some utility method. It worked, but the performance was surprisingly low. Passing a string to a function is 10x times faster than overriding the String.prototype
method that is doing the same thing. To make sure this really happens I created a very simple count()
function and the corresponding methods.
(I was experimenting, and created three different versions of the method.)
function count(str, char) {
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
String.prototype.count = function (char) {
var n = 0;
for (var i = 0; i < this.length; i++) if (this[i] == char) n++;
return n;
}
String.prototype.count_reuse = function (char) {
return count(this, char)
}
String.prototype.count_var = function (char) {
var str = this;
var n = 0;
for (var i = 0; i < str.length; i++) if (str[i] == char) n++;
return n;
}
// Here is how I measued speed, using Node.js 6.1.0
var STR ='0110101110010110100111010011101010101111110001010110010101011101101010101010111111000';
var REP = 1e3//6;
console.time('func')
for (var i = 0; i < REP; i++) count(STR,'1')
console.timeEnd('func')
console.time('proto')
for (var i = 0; i < REP; i++) STR.count('1')
console.timeEnd('proto')
console.time('proto-reuse')
for (var i = 0; i < REP; i++) STR.count_reuse('1')
console.timeEnd('proto-reuse')
console.time('proto-var')
for (var i = 0; i < REP; i++) STR.count_var('1')
console.timeEnd('proto-var')
Results:
func: 705 ms
proto: 10011 ms
proto-reuse: 10366 ms
proto-var: 9703 ms
As you can see the difference is dramatic.
The below proves that performance of method calls is neglectably slower, and that the function code it self is slower for methods.
function count_dummy(str, char) {
return 1234;
}
String.prototype.count_dummy = function (char) {
return 1234; // Just to prove that accessing the method is not the bottle-neck.
}
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
console.time('proto-dummy')
for (var i = 0; i < REP; i++) STR.count_dummy('1')
console.timeEnd('proto-dummy')
console.time('func-dummy')
for (var i = 0; i < REP; i++) count_dummy(STR,'1')
console.timeEnd('func-dummy')
Results:
func-dummy: 0.165ms
proto-dummy: 0.247ms
Although on huge repetitions (like 1e8) prototyped methods proves to be 10x times slower than functions, this can be ignored for this case.
All this may be related only to a String object, because simple generic objects perform about the same when you pass them to functions or call their methods:
var A = { count: 1234 };
function getCount(obj) { return obj.count }
A.getCount = function() { return this.count }
console.time('func')
for (var i = 0; i < 1e9; i++) getCount(A)
console.timeEnd('func')
console.time('method')
for (var i = 0; i < 1e9; i++) A.getCount()
console.timeEnd('method')
Results:
func: 1689.942ms
method: 1674.639ms
I've been searching on Stackoverflow and binging, but other that the remendation "do not extend String or Array because you pollute the name space" (which is not a problem for my particular project), I cannot find anything related to performance of methods pared to functions. So should I simply forget about extending the String object due to performance drop of added methods or there is more about it?
Share Improve this question asked Jul 16, 2016 at 4:36 exebookexebook 34.1k42 gold badges152 silver badges241 bronze badges 1-
Thanks for your information but, you're last implementation is far away from
prototype
you can replace object with function and then add prototype method. then get a new instance of it. BTW result is the same. – Morteza Tourani Commented Jul 16, 2016 at 5:37
1 Answer
Reset to default 10This is most likely because you are not using strict mode, and the this
value inside your method is getting coerced to a String
instance instead of being a primitive string. This coercion, and further method calls or property accesses on the String
object, are slower than using primitive values.
You can (Edit: could, at least, in 2016) confirm this by repeating your measurement on var STR = new String('01101011…')
which should have less overhead.
Then fix your implementation:
String.prototype.count = function (char) {
"use strict";
// ^^^^^^^^^^^^
var n = 0;
for (var i = 0; i < this.length; i++)
if (this[i] == char)
n++;
return n;
};
版权声明:本文标题:javascript - Extending String.prototype performance shows that function calls are 10x faster - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744193046a2594608.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论