Q: 什么是 Node.JS ?
A:Node.JS 是指运于 web 服务端的 JavaScript, 基于 Chrome V8 引擎, 有非阻塞, 事件驱动 I/O 等特性.
Q: 等等, 你刚提到了 Chorme V8 引擎, 它是什么, 为什么使用它而不是其它引擎?
A:JavaScript 引擎是执行 JavaScript 代码的程序或解释器, JavaScript 引擎可以实现为标准解释器, 或者以某种形式将 JavaScript 编译为字节码的即时编译器. 它的工作流程大致如下:
Chorme V8 引擎便是其中一种, 由 Google 开发, 使用 C++ 编写, 它的工作流程几乎与上图一致:
相比于其它 JavaScript 引擎转换成字节码或者解释执行, V8 将 JavaScript 代码转换成更高效的机器码 (IA-32, x86-64, ARM, or MIPS CPUs). 它通过 JIT(Just-In-Time) 编译器实现, 不生成字节码或任何中间代码. 并且使用了如 Inlining,Shapes,Inline Caches 等方法来提高性能.
Q: 很好, 现在我已经了解一点 Chorme V8 引擎有什么用了, 但是你列举的那些方法, 真让我头大.
A: 比如 Shapes 与 Inline Caches 用来优化对象属性加载.
Q: 嗯?
A:ECMAScript 规范基本上将所有对象定义为由字符串键值映射到 property 属性的字典, 其中 [[]] 双方括号是规范定义不能直接暴露给 JavaScript 的属性的表示方法.
Q: 在内存中也是这么存储?
A: 不不不, 如果在内存中这么存储, 那就浪费空间了. 比如说有相同形状的对象 object = { x: 7, y: 8 }, 它们的属性名是相同的, 并且在属性值的完整字典中, 也只有 [[value]] 不同.
Q: 那应该分开存储, 把除 [[value]] 之外的所有属性名和其余特性单独存储. 并且它需要有一个属性, 来告知 JavaScript 引擎去哪查找具体的值.
A: 是的, 引擎将对象的 Shape 分开存储, 如下 JSObject 只是存储 [[value]],Shape 中有一个 Offset 偏移量来告知 JavaScript 取哪找具体的值:
当有多个具有相同形状对象时, 优势变得清晰可见. 因为只需要将它们的形状与键值属性信息存储一次!
Q: 原来是这样, 不过那和 Inline Caches 有什么关系?
A: 关系大了, Shapes 主要是用来实现 Inline Caches(ICs)的, Inline Caches 是 JavaScript 快速运行的关键因素之一.
Q:
A: 比如有一个从对象中获取 x 属性的函数, 在 JSC(JavaScriptCore) 中执行时, 会生成以下字节码:
Inline Caches 在第一个指令 get_by_id 指令中, 由两个未初始化的插槽组成.
当调用函数 getX({ x: 'a' }) 时, 像前面所说, 对象 { x: 'a' } 有一个包含属性 x 的 Shape, 该 Shape 包含属性 x 的偏移量和其它特性, 当第一次执行该函数时, 会把该属性的 Shape 和 偏移量存储在 Inline Caches 中:
后续调用该函数时, Inline Caches 只需要对比 Shape, 如果与以前相同, 则只需要从偏移量加载该属性值. 这比每次查找要快很多.
Q: 很精彩!
A:V8 所做的, 远不止这些, 在即将要发布的 7.2 版本中, 解析时间明显降低, 缩短加载时间, 提高响应速度:
Q: 好了, 咱们不说 V8 了, 我对你前面提到的非阻塞和事件驱动 I/O 挺感兴趣的.
A:......
参考
JavaScript 引擎基础: Shapes 和 Inline Caches
V8 v7.2 发布 https://v8.js.cn/blog/v8-release-72/
How JavaScript works: inside the V8 engine + 5 tips on how to write optimized code
来源: https://juejin.im/post/5c24c9d66fb9a049f43b60da