Mat*_*ood 1 javascript optimization v8
从这篇旧文章中阅读 V8(微)优化 并引用:
始终以相同的顺序初始化对象成员
问题:在下面的示例中,始终以相同顺序初始化对象成员是什么意思?
function Point(x, y) {
this.x = x; // this.x = x line first because x is the first arg
this.y = y; // this.y = y line second because y is the second arg
}
var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
// At this point, p1 and p2 have a shared hidden class
p2.z = 55;
// warning! p1 and p2 now have different hidden classes!
Run Code Online (Sandbox Code Playgroud)
更长的报价:
JavaScript 具有有限的编译时类型信息:类型可以在运行时更改,因此很自然地期望在编译时推理 JS 类型的成本很高。这可能会让您质疑 JavaScript 的性能如何能够接近 C++。但是,V8 在运行时为对象内部创建了隐藏类型;具有相同隐藏类的对象可以使用相同的优化生成代码。
直到对象实例 p2 添加了额外的成员“.z”,p1 和 p2 在内部具有相同的隐藏类 - 因此 V8 可以为操作 p1 或 p2 的 JavaScript 代码生成优化程序集的单个版本。您越能避免导致隐藏类发散,您将获得更好的性能。
所以:
初始化构造函数中的所有对象成员(这样实例以后不会改变类型)
始终以相同的顺序初始化对象成员
注意:我在 C++ 中发现了类似的问题,但我无法真正阅读它为什么我应该按照声明的顺序初始化成员变量?
V8 开发人员在这里。首先,这个 JavaScript 性能建议与 C++ 的成员初始化规则完全无关。它也与构造函数参数的顺序无关,即从引擎性能的角度来看,以下内容完全没问题:
function Point(x, y) {
this.y = y; // Nothing wrong with this.
this.x = x;
}
Run Code Online (Sandbox Code Playgroud)
“以相同顺序初始化成员”的意思是该类型的所有实例都应该使用相同的初始化顺序。当它们都使用相同的简单构造函数时,这会自动发生——这很好,因为这意味着在大多数情况下,您不必担心这一点;你甚至不需要知道这些建议。
最常见的反例是使用对象字面量创建对象,而不关心其中的属性顺序。即使属性名称集相同,顺序对于隐藏类也很重要。考虑:
let p1 = {x: 1, y: 2};
let p2 = {y: 3, x: 4};
// p1 and p2 now have different hidden classes!
function get_x(point) { return point.x; }
get_x(point1);
get_x(point2);
Run Code Online (Sandbox Code Playgroud)
point.xget_x 中的负载现在需要处理两个隐藏类,这比每次看到相同的隐藏类要慢一些。
“始终使用构造函数”是避免这种情况的一个很好的经验法则;但是,这还不够精确,如下例所示:
function SillyPoint(x, y) {
if (x >= y) { // or any other condition
this.x = x;
this.y = y;
} else {
this.y = y;
this.x = x;
}
}
let p1 = SillyPoint(1, 2);
let p2 = SillyPoint(2, 1);
Run Code Online (Sandbox Code Playgroud)
尽管 p1 和 p2 使用相同的构造函数,但它们以不同的顺序初始化它们的成员,因此它们具有不同的隐藏类。与上面的示例一样,这会使需要同时处理 p1 和 p2 的函数中的属性加载速度稍慢。
| 归档时间: |
|
| 查看次数: |
134 次 |
| 最近记录: |