You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functiontest(use_new,add_first,set__proto__,same_map_as){varproto=use_new ? newSuper() : {};// New object is fast.assertTrue(%HasFastProperties(proto));if(add_first){AddProps(proto);// Adding this many properties makes it slow.assertFalse(%HasFastProperties(proto));DoProtoMagic(proto,set__proto__);// Making it a prototype makes it fast again.assertTrue(%HasFastProperties(proto));}else{DoProtoMagic(proto,set__proto__);// Still fastassertTrue(%HasFastProperties(proto));AddProps(proto);// After we add all those properties it went slow mode again :-(assertFalse(%HasFastProperties(proto));}if(same_map_as&&!add_first){assertTrue(%HaveSameMap(same_map_as,proto));}returnproto;}
// Set the new prototype of the object.Handle<Map> map(real_receiver->map());
// Nothing to do if prototype is already set.if (map->prototype() == *value) return value;
if (value->IsJSObject()) {
JSObject::OptimizeAsPrototype(Handle<JSObject>::cast(value));
}
voidJSObject::OptimizeAsPrototype(Handle<JSObject> object) {
if (object->IsGlobalObject()) return;
// Make sure prototypes are fast objects and their maps have the bit set// so they remain fast.if (!object->HasFastProperties()) {
MigrateSlowToFast(object, 0);
}
}
在 Bluebird 库中有一段匪夷所思的代码(/src/util.js):
所有的 javascript 最佳实践都告诉我们不要使用 eval。更奇怪的是,这段代码却在函数
return
之后又调用了 eval,于是添加了一行注释来禁止 jshint 的警告信息。那么这段代码真的有那么神奇,可以加速对象中属性的访问速度吗?
在 V8 引擎中,对象有 2 中访问模式:Dictionary mode(字典模式) 和 Fast mode(快速模式)。
当动态地添加太多属性、删除属性、使用不合法标识符命名属性,那么对象就会变为字典模式(基准测试)。
速度差了近 3 倍。
javascript 作为一名灵活的动态语言,开发者有很多种方式可以创建对象,还可以在创建完对象以后动态的添加和删除对象的属性,因此高效而灵活的表示一个对象比静态语言要困难很多。
根据 ECMA-262 标准,对象的属性都是字符串,即使使用了数字作为属性也会被转换为字符串。因此:
此时
a
对象的值是:V8 中所有的变量都继承 Value。原始值都继承 Primitive,对象的类型为 Object,继承 Value,函数的类型为 Function,继承 Object。而原始值的包装类也都有各自的类型,比如 Number 的包装类是 NumberObject,也继承 Object。
Object
的属性通过 2 中方式访问:在快速模式下对象的
properties
是由Heap::AllocateFixedArray
创建的普通FixedArray
。在字典模式下,对象的properties
是由NameDictionary::Allocate
创建的NameDictionary
。在视频
https://www.youtube.com/watch?v=hWhMKalEicY
中,V8 的开发者 Lars Bak 解释了对象的两种访问模式以及快速模式是如何运行的。Vyacheslav Egorov 的 Understanding V8 中 Understanding Objects 章节也解释了 Hidden Class 是如何工作的。
当一个 JS 对象被设置为某个函数的原型的时候,它会退出字典模式:
我们可以看看 V8 源码中关于 fast-prototype 的测试用例:
如果觉得难懂,直接看我加粗的注释,我们可以知道:
prototype
,变 fast因此 Bluebird 代码中
f.prototype = obj
是使属性访问变快的关键。当把一个对象设置为另一个对象的prototype
时,V8 引擎对对象的结构重新进行了优化。V8 中关于对象的代码定义在 objects.cc 中:
JSObject::MigrateSlowToFast
将对象的字典模式变成了快速模式。https://v8.paulfryzel.com/docs/master/classv8_1_1internal_1_1_j_s_object_a663c5f054f780e77e595402eef1c4d1e_cgraph.svg
。MigrateSlowToFast 的源码比较长,原理就是使用
FixedArray
替换了NameDictionary
。在 SetPrototype 函数中有一段:
OptimizeAsPrototype 的代码:
相关阅读:
欢迎订阅我的微信公众帐号 (justjavac-blog):
The text was updated successfully, but these errors were encountered: