Xtr*_*der 7 javascript performance
在对我的库中的代码进行基准测试时,我发现了非常有趣且令人失望的发现 - 看起来类方法的调用比相同独立函数的调用慢 20-40 倍。
简而言之,对我来说,这意味着“为了更好的性能,不要通过 JS 类实现非常频繁调用的功能”。通过“命名空间对象”访问库函数也会带来性能损失。这个问题可能会影响设计库的方法。
我觉得我错过了一些东西。如果下面的性能测试有问题,请告诉我。
以下是结果摘要,Windows + intel 9600k(nodejs 14、Chrome 86、FF82)
ops/s in: node14 slow Ch86 slow FF82 slow
function(a, b) 4195 3934 1625
namespace.method(a, b) 210 x20 2702 x1.5 1305 x1.24
instance.method(a, b) 126 x33 162 x24 89 x18
prototype.method(a, b) 105 x40 154 x25 57 x28
class.method(a, b) 110 x38 153 x25 57 x28
Run Code Online (Sandbox Code Playgroud)
https://benchmarkjs.com/的测试脚本,部分内容也复制/粘贴到https://jsbench.me/以进行浏览器内测试。
const Benchmark = require('benchmark');
const suite = new Benchmark.Suite("function-vs-method");
const nCycles = 1000000;
suite
.add('function(a, b)', function () {
function method(a, b) {
return a + b;
}
for( let i = 0; i < nCycles; i++ ) {
method(i, i)
}
})
.add('namespace.method(a, b)', function () {
function method(a, b) {
return a + b;
}
let namespace = {}
namespace.method = method
for( let i = 0; i < nCycles; i++ ) {
namespace.method(i, i)
}
})
.add('instance.method(a, b)', function () {
function method(a, b) {
return a + b;
}
function Test() {}
let instance = new Test()
instance.method = method
for( let i = 0; i < nCycles; i++ ) {
instance.method(i, i)
}
})
.add('prototype.method(a, b)', function () {
Test.prototype.method = (a, b) => {
return a + b;
}
function Test() {
}
let proto = new Test()
for( let i = 0; i < nCycles; i++ ) {
proto.method(i, i)
}
})
.add('class.method(a, b)', function () {
class Test {
method(a, b) {
return a + b;
}
}
let c = new Test()
for( let i = 0; i < nCycles; i++ ) {
c.method(i, i)
}
})
// add listeners
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').map('name'));
})
.run();
Run Code Online (Sandbox Code Playgroud)
您在测试中包含初始化,而不仅仅是比较方法/函数调用。
\n示例:您正在比较“声明和调用函数”与“声明类、实例化类对象并调用类方法”。
\n如果您在实际测试之外提取设置,结果看起来会完全不同。
\nnCycles此外,每次使用for 循环运行代码都会产生完全不同的结果。我将其更改为一次调用,现在在测试运行中看到了恒定的结果。
免责声明:到目前为止,我还没有做太多基准测试,但想尽力给出答案。@大家请随意解释为什么我可能走错了路。@op请不要盲目相信这个答案。
\nconst Benchmark = require(\'benchmark\');\nconst suite = new Benchmark.Suite(\'function-vs-method\');\n\nfunction method (a, b) {\n return a + b;\n}\n\nlet namespace = {};\nnamespace.method = function (a, b) {\n return a + b;\n};\n\n\nfunction Test () {\n}\n\nlet instance = new Test();\ninstance.method = function (a, b) {\n return a + b;\n};\n\n\nTestProto.prototype.method = function (a, b) {\n return a + b;\n};\n\nfunction TestProto () {\n}\n\nlet proto = new TestProto();\n\nclass TestClass {\n method (a, b) {\n return a + b;\n }\n}\n\nlet c = new TestClass();\n\nsuite\n .add(\'function(a, b)\', function () {\n method(1, 2);\n })\n .add(\'namespace.method(a, b)\', function () {\n namespace.method(1, 2);\n })\n .add(\'instance.method(a, b)\', function () {\n instance.method(1, 2);\n })\n .add(\'prototype.method(a, b)\', function () {\n proto.method(1, 2);\n })\n .add(\'class.method(a, b)\', function () {\n c.method(1, 2);\n })\n // add listeners\n .on(\'cycle\', function (event) {\n console.log(String(event.target));\n })\n .on(\'complete\', function () {\n console.log(\'Fastest is \' + this.filter(\'fastest\').map(\'name\'));\n })\n .run();\nRun Code Online (Sandbox Code Playgroud)\n日志:
\nfunction(a, b) x 1,395,900,922 ops/sec \xc2\xb10.11% (93 runs sampled)\nnamespace.method(a, b) x 1,397,715,256 ops/sec \xc2\xb10.06% (98 runs sampled)\ninstance.method(a, b) x 1,397,494,031 ops/sec \xc2\xb10.08% (96 runs sampled)\nprototype.method(a, b) x 1,395,546,437 ops/sec \xc2\xb10.09% (98 runs sampled)\nclass.method(a, b) x 1,398,311,922 ops/sec \xc2\xb10.07% (96 runs sampled)\nFastest is class.method(a, b),namespace.method(a, b),instance.method(a, b),function(a, b)\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2351 次 |
| 最近记录: |