Javascript分析之谜 - 闭包变量

Javascript profiling mystery - closure variables

本文关键字:闭包 变量 Javascript      更新时间:2023-09-26

我正在测试在闭包中定义变量的情况下的性能(使用 chrome 时间线(。因此,它的值不会向用户公开。

正如预期的那样,run_proto_fn运行速度快了几倍,垃圾回收最少,内存堆也很低。

run_proto_obj恰好恰恰相反,好像在对象原型属性属性中使用非函数值的成本很高。

有人可以在这里分享一些澄清吗?

SOME = function(){};
SOME.prototype.exe = function(v){
	var x = {
		a:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
		b:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
		c:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	};
	return x[v];
};
SOME2 = function(){};
SOME2.prototype.exe = function(v){
	return this.exes[v];
};
SOME2.prototype.exes = {
	a:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	b:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
	c:'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea, quae repudiandae eveniet cumque consequatur vitae aut. Nisi perspiciatis magnam explicabo optio reprehenderit dignissimos at porro quam, neque dolorum, architecto odit?',
};
SOME_FN = function(){};
SOME_FN.prototype.exe = function(v){
	var x = {
		a: function(p){this.p1 = p;return this;},
        b:function(p){this.p2 = p*3;return this;},
        c:function(p){this.p3 = p*99;return this;},
    };
  return x[v].call(this,42);
};
SOME_FN2 = function(){};
SOME_FN2.prototype.exe = function(v){
    return this.exes[v].call(this,42);	
};
SOME_FN2.prototype.exes = {
    a: function(p){this.p1 = p;return this;},
    b:function(p){this.p2 = p*3;return this;},
    c:function(p){this.p3 = p*99;return this;},
};
var a1 = a2 = a_fn1 = a_fn2 = [];
	
var run_local_obj = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x1 = new SOME();
		x1.exe('a');
		a1.push(x1);
	}
};
var run_proto_obj = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x2 = new SOME2();
		x2.exe('a');
		a2.push(x2);
	}
};
var run_local_fn = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x1 = new SOME_FN();
		x1.exe('a');
		x1.exe('b');
		x1.exe('c');
		a_fn1.push(x1);
	}
};
var run_proto_fn = function(){
	for (var i = 1000000 - 1; i >= 0; i--) {
		x2 = new SOME_FN2();
		x2.exe('a');
		x2.exe('b');
		x2.exe('c');
		a_fn2.push(x2);
	}
};
<button onclick="run_local_obj(this)">local obj</button>
<button onclick="run_proto_obj(this)">proto obj</button>
<button onclick="run_local_fn(this)">local obj FN</button>
<button onclick="run_proto_fn(this)">proto obj</button>


我听过一句话:

每次函数运行时定义闭包变量

但是,我仍然没有雾。

我尝试运行测量,首先我注意到的是,仅使用您问题中的代码很难理解发生了什么。

如果我一个接一个地运行这些测试(单击按钮并查看时间线(,那么对于下一次运行,结果会有很大差异。从几次运行来看,第三(run_local_fn(通常比其他运行更长。

然后我尝试以倒序运行它们(从 4 到 1 单击按钮(并得到完全不同的结果 - run_local_obj最长。

所以我稍微修改了测试代码,以便能够获得稳定的结果。

完整代码在这里,您可以克隆存储库并在本地进行测试。

以下是我在 Chrome 中运行每个测试的方式(我使用 js-perf-test 文件夹中的python -m SimpleHTTPServer 8082启动了它(:

  • 使用 http://localhost:8082/perf.html 打开选项卡,打开开发工具
  • 开始时间线录制
  • 单击按钮
  • 在控制台中等待结果(最小值/最大值/平均值(
  • 停止时间线录制

结果稳定且可重复(时序和时间线视图(,以下是测试之一:

  • "run_local_obj" - 508.45ms,时间轴
  • "run_proto_obj" - 433.11ms,时间轴
  • "run_local_fn" - 756.26ms,时间轴
  • "run_proto_fn" - 560.62ms,时间轴

所以我们在这里看到的是:

1(run_proto_obj最快,run_local_obj接近它。

我认为run_proto_obj应该是最有效的,因为它使用带有字符串的静态定义的对象。而且JS引擎可能能够优化run_local_obj,所以x对象是重用的,而不是每次都创建的。

2(run_local_fn最慢。

这里我们有本地x对象和动态字符串计算,比其他测试更floating部分。

3(run_proto_fnrun_local_fn快,但比前两个函数慢。

我认为这也是意料之中的,带有a, b, c的对象只定义一次(因此它比run_local_fn快(。

与前两个函数相比,它动态计算生成的字符串,因此速度较慢。

所以回到你的问题:

正如预期的那样,run_proto_fn运行速度快了几倍,垃圾回收最少,内存堆也很低。 但run_proto_obj恰好恰恰相反,好像在对象原型属性属性中使用非函数值的成本很高。

在我看来,您只是没有正确设置实验。根据上面的结果,run_proto_obj实际上是最快的。

更新:我刚刚在Firefox中尝试了相同的测试,结果相似:

  • "run_local_obj" - 344.85ms
  • "run_proto_obj" - 151.47ms
  • "run_local_fn" - 788.08毫秒
  • "run_proto_fn" - 265.21ms

run_proto_obj最快,run_local_fn最慢。