v9.4

发布信息

发布时间:2021.09.06
Chrome 同步版本:Chrome 94
链接:V8 release v9.4

JavaScript 新特性

1. class 支持类静态初始化块

新的类静态初始化块语法,提供了一个单独的位置,来存放给定的类初始化时应该运行一次的代码。

  1. class MyPRNG {
  2. constructor(seed) {
  3. console.log('constructor');
  4. if (seed === undefined) {
  5. if (MyPRNG.entropyPool.length === 0) {
  6. throw new Error('Entropy pool exhausted');
  7. }
  8. seed = MyPRNG.entropyPool.pop();
  9. }
  10. this.seed = seed;
  11. }
  12. static entropyPool = [];
  13. static {
  14. for (let i = 0; i < 512; i++) {
  15. this.entropyPool.push(i);
  16. }
  17. console.log('static block');
  18. }
  19. }

可以看到类静态初始化块,在类 MyPRNG 初始化时就进行了块内的计算:
image.png
从 v9.4开始,类静态初始化块将不需要 -- harmony-class-static-blocks 标志。

v9.3

发布信息

发布时间:2021.08.09
Chrome 同步版本:Chrome 93
链接:V8 release v9.3

JavaScript 新特性

1. Sparkplug 批量编译

V8 在 v9.1 中发布了超快的新中间层 JIT 编译器 Sparkplug。出于安全原因,V8 write-protectes (W^X) 代码内存生成时,要求在可写 (编译期间) 和可执行之间翻转权限。这是当前使用 mprotect 调用实现的。然而,由于 Sparkplug 生成代码的速度非常快,因此为每个单独的编译函数调用 mprotect 的成本成为编译时间的主要瓶颈。在 V8 v9.3中,我们引入了 Sparkplug 的批量编译: 我们不是单独编译每个函数,而是在批量中编译多个函数。这可以通过每批只翻转一次内存页面权限来分摊这种操作的成本。
批量编译可以减少总的编译时间 (Ignition + Sparkplug) 高达44% ,而无需回溯 JavaScript 的执行。如果我们只看编译 Sparkplug 代码的成本,影响显然更大,例如 Win 10上的 docs_scrolling 基准 (见下文) 减少了82% 。令人惊讶的是,批处理编译比 W^X 的成本提高了更多的编译性能,因为将类似的操作批处理在一起对 CPU 来说更好。在下图中,你可以看到 W^X 对编译时间的影响 (Ignition + Sparkplug)) ,以及批量编译如何减轻这种开销。
image.png

2. Object.hasOwn

Object.hasOwnObject.prototype.hasOwnProperty.call 更易记的别名(查看特性解释)。

  1. Object.hasOwn({ prop: 42 }, 'prop')
  2. // → true

3. Error 新增属性 cause

从 v9.3 开始,对各种内置的 Error 构造函数进行了扩展,可以接受第二个参数包含 cause 属性的可选项。如果传递了这样的可选项,则 cause 属性的值将作为 Error 实例上自己的属性。这为错误链提供了一种标准化的方法(查看特性解释):

  1. const parentError = new Error('parent');
  2. const error = new Error('parent', { cause: parentError });
  3. console.log(error.cause === parentError);
  4. // → true
  1. function doWork() {
  2. try {
  3. doSomeWork();
  4. } catch (err) {
  5. throw new Error('Some work failed', { cause: err });
  6. }
  7. try {
  8. doMoreWork();
  9. } catch (err) {
  10. throw new Error('More work failed', { cause: err });
  11. }
  12. }
  13. try {
  14. doWork();
  15. } catch (err) {
  16. switch(err.message) {
  17. case 'Some work failed':
  18. handleSomeWorkFailure(err.cause);
  19. break;
  20. case 'More work failed':
  21. handleMoreWorkFailure(err.cause);
  22. break;
  23. }
  24. }