有没有办法胜过下面的方法? (a 和 b 的类型已知 - unsigned int 32 位):
function f() {
var a = /*calculate a*/;
var b = /*calculate b*/;
return [a, b];
}
这样会更快吗?是的,我知道,下面的代码很糟糕。但我们的想法是避免创建新对象(如第一个示例中返回的数组)。
// set of general-purpose registers for UINT32 values.
var global_registers = new Uint32Array(256);
function f() {
global_registers[0] = a;
global_registers[1] = b;
}
// Usage:
f();
//use the global_registers[0] and global_registers[1].
最佳答案
从您提供的两个版本的代码来看,第二个版本更快。但这并不意味着类型化数组的使用有所不同。您还切换到全局变量,改变它们而不是创建新条目,并且不要让您的函数返回任何内容。
以下是这些变体的性能测试:
- 您的原始阵列解决方案
使用普通对象代替数组
function f_obj() { var a = 1; var b = 2; return {a, b}; }
使用全局普通对象作为参数传递
function f_obj_inplace(obj) { var a = 1; var b = 2; obj.a = a obj.b = b; }
您最初的全局“注册”解决方案
使用标准的全局对象
var global_obj = { a: 0, b: 0}; function f_glob_obj() { var a = 1; var b = 2; global_obj.a = a; global_obj.b = b; }
//////////////////////////////////////
function f_arr() {
var a = 1;
var b = 2;
return [a, b];
}
//////////////////////////////////////
function f_obj() {
var a = 1;
var b = 2;
return {a, b};
}
//////////////////////////////////////
var global_registers = new Uint32Array(256);
function f_glob_reg() {
var a = 1;
var b = 2;
global_registers[0] = a;
global_registers[1] = b;
}
//////////////////////////////////////
var global_obj = { a: 0, b: 0};
function f_glob_obj() {
var a = 1;
var b = 2;
global_obj.a = a;
global_obj.b = b;
}
var iterations = 1000000;
var o, result;
/////////////////////
var start = performance.now();
for(var i = 0; i < iterations; i++) {
o = f_arr();
result = o[0];
}
console.log('f_arr', (performance.now() - start).toFixed(2));
/////////////////////
var start = performance.now();
for(var i = 0; i < iterations; i++) {
o = f_obj();
result = o.a;
}
console.log('f_obj', (performance.now() - start).toFixed(2));
/////////////////////
var obj = { a: 0, b: 0 };
var start = performance.now();
for(var i = 0; i < iterations; i++) {
f_obj(obj);
result = obj.a;
}
console.log('f_obj_inplace', (performance.now() - start).toFixed(2));
/////////////////////
var start = performance.now();
for(var i = 0; i < iterations; i++) {
f_glob_reg();
result = global_registers[0];
}
console.log('f_glob_reg', (performance.now() - start).toFixed(2));
/////////////////////
var start = performance.now();
for(var i = 0; i < iterations; i++) {
f_glob_obj();
result = global_obj.a;
}
console.log('f_glob_obj', (performance.now() - start).toFixed(2));
/////////////////////
这是我在 Firefox 和 Chrome 上的典型运行:
Function | Firefox 47 | Chrome 52
------------------+------------+----------
1. f_arr | 501 | 206
2. f_obj | 202 | 172
3. f_obj_inplace | 17 | 69
4. f_glob_reg | 19 | 34
5. f_glob_obj | 22 | 31
结果应该有一定的误差范围,因为它们会根据 PC 负载在每次运行时发生变化。
这些结果表明,普通对象解决方案 (2) 比数组解决方案 (1) 更快。值得注意的是,在 Firefox 上,数组解决方案要慢得多。
我们还可以看到,使用就地变异的全局变量(3、4 和 5)带来了巨大的性能提升。当将全局对象作为函数参数传递时,Chrome 确实仍然有一些性能损失 (3),而对于 Firefox 来说几乎没有任何区别。
但更重要的是,从最后两次测量中,我们看到未类型化的全局变量解决方案与原始类型化全局变量解决方案的速度差不多。
备注
出于已知原因,不建议在函数内使用全局变量:它会使代码模块化程度降低、更难阅读和更难调试。
如果你想每次都在同一个地方存储数据的性能优势,那么将变量作为参数传递给函数:这样做的性能损失似乎在可接受的范围内(尽管 Firefox 似乎处理得更好与 Chrome 相比)。
函数总是写入相同的全局变量,破坏了之前的结果,这可能过于严格。如果您最终将结果复制到别处以防止它们被覆盖,您将因此再次增加开销。
类型化数组的使用并不是真正的性能决定性因素。
结论
以上结果和考虑让我建议第三个选项:
function f_obj_inplace(obj) {
var a = 1;
var b = 2;
obj.a = a
obj.b = b;
}
您没有丑陋的直接访问全局变量的权限,也没有使用类型化数组。但是您确实使用就地突变和普通对象而不是数组。
关于javascript - JS : fastest way to return 2 numbers from function?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38679153/