为了账号安全,请及时绑定邮箱和手机立即绑定

Chrome V8 与 Node.js

从某种意义上来说,Node.js 并不是一个从零开始编写的 JavaScript 运行时,它其实也是站在“巨人的肩膀”上进行了一系列的拼凑和封装得到的结果。它的高效离不开一些很牛的第三方程序和类库。比如本文我们介绍的Chrome V8。

Chrome V8 简称 V8,是由谷歌开源的一个高性能 JavaScript 引擎。该引擎采用 C++ 编写,Google Chrome 浏览器用的就是这个引擎。V8 可以单独运行,也可以嵌入 C++ 应用当中。

webp

和其他的 JavaScript 引擎一样,V8 会编译、执行 JavaScript 代码,并一样会管理内存、垃圾回收等。

就是因为 V8 的高性能以及跨平台等特性,所以它也是 Node.js 的 JavaScript 引擎。

高效

V8 开发小组由一群程序语言专家组成。其中核心工程师 Lars Bak 之前在 Sun 公司工作,专注于 Java 虚拟机加速技术的研究,产出了 HotSpot,除此之外,他还曾开发了 Strongtalk1。

所以,V8 的代码里面蕴含了从 HotSpot 和 Strongtalk 中汲取的精髓。

该研发小组从 2006 年开始研发 V8,原因是当年市面上的各种 JavaScript 引擎效率都比较低下。在 Lars Bak 等人的贡献下,JavaScript 引擎添加了新的一员—— Chrome V8,并且效率非常高。

V8 的高效主要体现在以下 4 个特性上面。

(1) JIT 编译

JIT 编译,全称 Just-In-Time 编译,也就是即时编译。它编译出的结果直接是机器语言,而不是字节码。这样大大提高了 V8 在执行 JavaScript 时的效率。不过后来其他的几家 JavaScript引擎也渐渐推出了对 JIT 的支持。

(2) 垃圾回收

这个特性在 Java 领域中使用得比较多。虽然其他语言或者其他的 JavaScript 引擎实现都有垃圾回收,但是 V8 的垃圾回收借鉴了 Java VM 的精确垃圾回收管理,而其他很多语言的垃圾回收用的是保守垃圾管理。

相较而言,V8 的这套垃圾回收机制的效率要远远高于其他一些垃圾回收机制实现——实际上代价就是这种机制的实现难度更大。

(3) 内联缓存(Inline Cache)

V8 使用了内联缓存的特性来提高属性的访问效率。如有一个访问是 this. 蛋花汤,没有内联缓存的时候,每次要取蛋花汤的话都会对哈希表进行一次寻址,而加入了内联缓存的特性之后,V8 能马上知道这个属性的一个偏移量,而不用再次计算寻址的偏移量了。

(4) 隐藏类

由于 JavaScript 是一门动态的编程语言,因此哪怕是在 ES6 及以上版本的规范中有了class 的一个定义,开发者也能非常方便地对一个对象添加或者移除一个属性。

隐藏类就是对这样一套对象体系中的一个黑科技的包装——所有如属性一样的对象会被归为同一个隐藏类。

下面举个简单的例子:

webp

一开始根据 Pet 创建了 蛋花汤 这个对象。在最开始初始化的时候 V8 就会创建一个隐藏类(假设是 P0),这是一个空类,因为它还没有任何的属性;后来 this.type = type 执行了,隐藏类就有了 type 属性,这个时候就又多了一个 P1 的隐藏类——P1 是基于 P0 创建的,并且多了 type 属性;接着,name 被赋值上去,于是隐藏类又多了一个 P2。

然后在创建 南瓜饼 对象的时候,又走了上面的老路,只不过这次不是创建隐藏类 P0、P1和 P2 了,而是直接沿用它们。在初始化 南瓜饼 的时候,它依次会属于上面创建的3 个隐藏类,直到最后它跟 蛋花汤 一样都属于 P2。

最后一行代码在给 蛋花汤 赋值 age 的时候,又一个新的隐藏类 P3 会被创建。这个时候 蛋花汤 和 南瓜饼 分别属于 P3 和 P2。这些描述分别如下图。

webp

最开始的蛋花汤和南瓜饼隐藏类归属


webp

赋值 type 后的蛋花汤和南瓜饼隐藏类归属


webp

赋值 name 后的蛋花汤和南瓜饼隐藏类归属


webp

最终的蛋花汤和南瓜饼隐藏类归属

隐藏类和内联缓存这两把“匕首”联合起来,是 V8 高效的一个非常重要的原因,因为同一个隐藏类的对象们能用同一套内联缓存来寻址。

遵循 ECMAScript

在当前 V8 的项目主页中,有一句话表明了它是遵循 ECMA-262 标准的:

“V8 implements ECMAScript as specified in ECMA-262.”

就目前来说 ECMA-262 标准(曾)发布了 7 个大版本。

webp

webp

Generator 函数的爱称,因其有一个显著的标识——形如菊花的星号(*)而得名。

V8 在开发的过程中也一直追着 ECMAScript 发布的脚步,如基本上完成了对 ES6 的支持,而且最新版也对 async/await 函数进行了支持。

也正是因为 V8 对 ECMAScript 标准紧追不舍,才有了 Node.js 能及时跟上 ECMAScript 最新语法的情况。如 Node.js 7.6 正式默认支持 async/await 功能就是沾了 V8 的光。

Node.js 与 Chrome V8

下面是 V8 与 Node.js 的部分版本对照表。

webp

webp

Node.js 一直紧跟 V8 的版本脚步在迭代。

Node.js 与 V8 实际上看起来更像是一对情侣,而不仅仅是 Node.js 一厢情愿地使用 V8 作为自己的底层支持。

在 Chrome V8 的博客中曾经有一篇文章名为《V8 Node.js》。Node.js 在几年发展中的流行度稳步增长,于是有了 V8 的“姑娘,你成功引起了我的注意”。现在 V8 也有一些工作是为 Node.js 而做的:

--在 Chrome 开发者工具中可以调试 Node.js;

--加速 ES6;

--针对 Node.js vm 模块和 REPL 的一些修复;

--Async / await。

本文选自《Node.js:来一打 C++ 扩展》



作者:博文视点
链接:https://www.jianshu.com/p/8290715feec6


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消