ECMAScript 双月报告:TC39 2022年12月会议提案进度汇总

简介: 在本次会议中,Intl.Enumeration 提案成功进入到 Stage 4,距离它在 2020 年 6 月的会议上进入到 Stage 1 已经过去了两年半的时间,其它备受关注的提案如 Explicit Resource Management 与 Set Methods也成功取得进展,进入到 Stage 3 阶段。Stage 3 → Stage 4从 Stage 3 进入到 Stage 4 有以

在本次会议中,Intl.Enumeration 提案成功进入到 Stage 4,距离它在 2020 年 6 月的会议上进入到 Stage 1 已经过去了两年半的时间,其它备受关注的提案如 Explicit Resource Management 与 Set Methods也成功取得进展,进入到 Stage 3 阶段。

Stage 3 → Stage 4

从 Stage 3 进入到 Stage 4 有以下几个门槛:

  1. 必须编写与所有提案内容对应的  tc39/test262测试,用于给各大 JavaScript 引擎和 transpiler 等实现检查与标准的兼容程度,并且 test262 已经合入了提案所需要的测试用例;
  2. 至少要有两个实现能够兼容上述 Test 262 测试,并发布到正式版本中;
  3. 发起了将提案内容合入正式标准文本  tc39/ecma262的 Pull Request,并被 ECMAScript 编辑签署同意意见。

Intl.Enumeration

提案链接:proposal-intl-enumeration

这一提案用于获取当前运行环境下国际化选项的支持值,如 calendar、currency、timeZone 等,其引入了 Intl.supportedValuesOf(key) 方法来返回对应的所有支持值,如获取当前运行环境中所有支持的历法:

console.log(Intl.supportedValuesOf('calendar')); 
// ['buddhist', 'chinese', 'coptic', 'dangi', ...]

Stage 2 → Stage 3

提案从 Stage 2 进入到 Stage 3 有以下几个门槛:

  1. 撰写了包含提案所有内容的标准文本,并有指定的 TC39 成员审阅并签署了同意意见;
  2. ECMAScript 编辑签署了同意意见。

Set Methods

提案链接:proposal-set-methods

此提案为 JavaScript 中的 Set 结构新增了一批内置方法,主要为集合相关,包括交集、并集、差集、子集等:

  • Set.prototype.intersection(other)
  • Set.prototype.union(other)
  • Set.prototype.difference(other)
  • Set.prototype.symmetricDifference(other)
  • Set.prototype.isSubsetOf(other)
  • Set.prototype.isSupersetOf(other)
  • Set.prototype.isDisjointFrom(other)

这些方法的入参均为另一个 Set 类型的数据,或者至少是实现了 .size .keys .has 三个方法的对象。

Well-formed Unicode strings

提案链接:proposal-is-usv-string

ECMAScript 字符串都是 UTF-16 编码的字符串。在 Web API 中,我们可以发现有些 API (如 URL、URLSearchParams 等等系列 API)都声明了需要 USVString 作为参数。什么是 USVString?USV 代表 Unicode Scalar Value,即 Unicode 标量值。根据 Unicode 定义,Unicode 的码位(Code Point)可以分成几个类别,分别是图形码(Graphic),格式码(Format),控制码(Control),私有码(Private-Use),代理码(Surrogate),非字符码(Noncharacter),与保留码(Reserved)。而其中的代理码又分成了高位代理码与低位代码码,只有当一个高位代码码与一个低位代理码组合成一个代理码对,才是一个合法的 Unicode 字符。

目前,JavaScript 字符串并不限制这个字符串的值是否是合法的 Unicode 值,比如我们可以编码一个字符串只有高位代理码,而没有低位代理码等等。而如严格的 Web URL API 定义必须要求参数字符串是合法的 Unicode 标量值,因此我们需要有方法能够去区分一个字符串是否是合法的 Unicode 标量值。

这个提案提出为 ECMAScript 引入新的内置方法 String.prototype.isWellFormed,  用于检查这个字符串是否是一个合法的 Unicode 标量值:

'\ud800'.isWellFormed(); // => false
'\ud800\udc00'.isWellFormed(); // => true

另外此提案也提供了 String.prototype.toWellFormed 方法,来将普通字符串转换到一个格式正确的 USV 字符串。类似的,NodeJs 中也提供了 util.toUSVString这样的方法来实现此功能。

你也可以使用其提供的 polyfill string.prototype.iswellformed和 string.prototype.towellformed来提前试用。

Explicit Resource Management

提案链接:proposal-explicit-resource-management

此提案旨在为 JavaScript 中引入显式的资源管理能力,通过统一的 using 关键字来标记当前块级作用域内的关键资源。

在此前,JavaScript 中对各种资源的管理方式并不统一,如在 Generator 函数中,通过 return 方法来提供执行清理逻辑的方式:

function * g() {
  const handle = acquireFileHandle();
  try {
    ...
  }
  finally {
    handle.release(); // 释放资源
  }
}

const obj = g();
try {
  const r = obj.next();
  ...
}
finally {
  obj.return(); // 显式调用函数 g 中的 finally 代码块
}

而通过 using 关键字,其可以被简化为如下的方式:

function * g() {
  using handle = acquireFileHandle(); // 定义与代码块关联的资源
}

{
  using obj = g(); // 显式声明资源
  const r = obj.next();
} // 自动调用释放逻辑

除此以外,NodeJs FileHandles 上的 handle.close() 方法,WHATWG Stream Readers 上的 reader.releaseLock() 均可以使用这种方式来简化资源的管理。

实际上,这里的“显式”对应的是此前如 WeakSet 与 WeakMap 这样,会由运行时作为垃圾回收的一部分进行的“隐式”工作。显式资源管理意味着用户主动声明块级作用域内依赖的资源,通过 Symbol.disposable这样的命令式或 using 这样的声明式,然后在离开作用域时自动地释放这些标记的资源。

Stage 1 → Stage 2

从 Stage 1 进入到 Stage 2 需要完成撰写包含提案所有内容的标准文本的初稿。

ArrayBuffer transfer

提案链接:proposal-arraybuffer-transfer

这一提案属于 proposal-resizablearraybuffer提案的衍生,其引入了 ArrayBuffer.prototype.transfer 方法,来支持对 ArrayBuffer 的所有权转移能力。

在 JavaScript 中,可转移对象指的是拥有可在不同上下文间转移的资源的对象,在转移资源后,原始上下文中的对象将不再指向资源,只有新的上下文持有资源的所有权。这一能力通常用于确保在同一时刻只有一个线程能够访问资源。更常见的一个例子是在 Web Worker 场景下,将可转让对象(比如一个 ArrayBuffer)在主线程与工作线程之间传递,传递方仍然持有原始 ArrayBuffer 对象,但其 byteLength 为0,同时无法再对其进行写入。这一过程无需经过任何拷贝操作,也就意味着在数据量较大时能够有明显的性能提升。

此前我们并不能直接将一个 ArrayBuffer 的资源所有权转移到另一个 ArrayBuffer 对象,以此来避免原始的缓冲区输入被篡改,而只能使用 slice 方法来复制一个 ArrayBuffer 对象,如以下这个例子:

function validateAndWriteSafeButSlow(arrayBuffer) {
	// 复制一份,避免缓冲区被篡改
  const copy = arrayBuffer.slice();

  await validate(copy);
  await fs.writeFile("data.bin", copy);
}

const data = new Uint8Array([0x01, 0x02, 0x03]);

validateAndWrite(data.buffer);

setTimeout(() => {
  // 篡改数据
  data[0] = data[1] = data[2] = 0x00;
}, 50);

这种方式需要将原本的 ArrayBuffer 中的每个字节进行复制,然后开辟新的缓冲区存放,在数据量较大将导致性能问题。而现在,我们可以使用 transfer 方法来直接转移其所有权,使得其无法被篡改:

function validateAndWriteSafeAndFast(arrayBuffer) {
  // 转移所有权,并直接移动而非复制数据
  const owned = arrayBuffer.transfer();

  assert(arrayBuffer.detached);

  await validate(owned);
  await fs.writeFile("data.bin", owned);
}

这里的 arrayBuffer.detached 属性也来自与此提案,用于作为一种清晰且权威的方式,来检查一个 ArrayBuffer 对象是否已从缓冲区分离。

Stage 0 → Stage 1

从 Stage 0 进入到 Stage 1 有以下门槛:

  1. 找到一个 TC39 成员作为 champion 负责这个提案的演进;
  2. 明确提案需要解决的问题与需求和大致的解决方案;
  3. 有问题、解决方案的例子;
  4. 对 API 形式、关键算法、语义、实现风险等有讨论、分析。 Stage 1 的提案会有可预见的比较大的改动,以下列出的例子并不代表提案最终会是例子中的语法、语义。

Intl MessageResource

提案链接:proposal-intl-message-resource

Intl MessageResource 提案是对 Intl.MessageFormat 提案的进一步补充,用于实现一次性对一组资源消息的翻译能力,这是因为 UI 界面中通常同时会存在一组相关联的消息需要翻译,如对话框等。

对于 Intl.MessageFormat 提案,我们的使用方式是这样的,首先给到 MF2 定义:

morning_greeting = {早上好,{$user}!}

new_notifications [$count] =
  [0]   你现在还没有信息
  [one] 你收到新信息了~
  [_]   你收到了 {$count} 条新信息,快打开看看吧!

MF2 的全称为 MessageFormat 2.0,是由message-format-wg制定的,统一的消息描述规范。它是编程语言无关的,目前实现了 MessageFormat 2.0 的语言主要包括 JavaScript和 Java

这里定义了无消息、单条消息、多条消息的几种情况,然后在 JavaScript 中就可以通过创建 Intl .MessageFormat 的实例,来进行消息的解析:

const resource = ... // 即以上的 MF2 定义
const mf1 = new Intl.MessageFormat(resource, ['en']);
const msg1 = mf.resolveMessage('new_notifications', { count: 3 });
msg1.toString(); // '你收到了 3 条新信息,快打开看看吧!'

const mf2 = new Intl.MessageFormat(resource, ['en']);
const msg2 = mf.resolveMessage('morning_greeting', { user: '小明' });
msg2.toString(); // '早上好,小明'

可以看到,对于同一个 MF2 定义,需要创建两个 Intl.MessageFormat 实例来分别进行解析。而 Intl Message Resource 提案为 Intl.MessageFormat 新增了 parseResource 静态方法,使得我们可以一次性完成对所有消息资源的解析:

const resource = ... // 即以上的 MF2 定义
const res = Intl.MessageFormat.parseResource(resource, ['en']);

const greeting = res.get('morning_greeting').resolveMessage({ user: '小明' });
greeting.toString(); // '早上好,小明'

const notifications = res.get('new_notifications').resolveMessage({ count: 3 });
notifications.toString(); // '你收到了 3 条新信息,快打开看看吧!'

另外,MessageFormatter 系列相关提案将引入的 API 具体格式还未完全确定,最终将取决于 MF2 工作组最终为 MF2 落地的语法。

Intl.era and monthCode

提案链接:proposal-intl-era-monthcode

这一提案属于 ECMAScript 402 中的 Intl 提案,与我们更熟悉的 Temporal 提案不同的是,Temporal 仅对 ISO8601 时间格式与 UTC 时区下的行为做了明确定义,对 ISO8601 以外的时间格式和 UTC 以外的时区,只提供了最基本的定义。而 Intl.era 提案旨在对这些规范细节进行进一步的完善。

这一提案之所以没有被作为 Temporal 提案的一部分,原因在于 Temporal 是 ECMA262 规范(即 ECMAScript)的一部分,其需要在所有支持 ECMAScript 的环境中运行并保持一致性,而 Intl 提案所属的 ECMAScript 402 作为 ECMAScript 的国际化标准,其在运行时可能会受到限制,如仅保留少数语言支持,此提案的行为也可能受到影响。

Mass Proxy Revocation

提案链接:proposal-mass-proxy-revocation

在 JavaScript 中,我们可以通过 Proxy.revocable 方法来创建一个可被撤销的代理对象,其返回值中将包含一个 revoke方法,调用此方法就将撤销掉一起生成的代理对象,而后续对此代理对象的所有可代理操作都将抛出错误。但这种方式仅适用于使用 revocable 方法创建的代理对象,同时需要为每个对象都调用一次 revoke方法。

而此提案引入了 createSignal 与 finalizeSignal 方法,来支持一次性对一批 Proxy 对象的撤销,甚至是直接通过 new Proxy 创建的代理对象也能够通过这种方式撤销,其使用方式大致如下:

const s1 = Proxy.createSignal();

const p1 = new Proxy([], {}, { signal: s1 });
const { proxy: p2, revoke } = Proxy.revocable({}, {}, { signal: s1 });

Proxy.finalizeSignal(s1); // p1 与 p2 都将被撤销

总结

对 ECMAScript 有新想法、新需求?快来了解 TC39 是如何工作的( https://yuque.antfin-inc.com/esnext/how-we-work/fgqi7o),或者直接与 @昭朗 联系,加入 ESNext 研讨会小组(钉钉群号23188462)与我们讨论。

相关文章
|
存储 域名解析 供应链
阿里云 OSS对象存储攻防
本文分为两个部分 第一部分介绍OSS对象存储攻防的方式 第二部分为真实漏洞案例
3268 0
阿里云 OSS对象存储攻防
计算机中存储单位的换算
计算机中存储单位的换算
|
缓存 Ubuntu Linux
LXC (Linux 虚拟环境)简单介绍
LXC是Linux containers的简称,操作系统级别的虚拟化技术。它可以在操作系统层次上为进程提供的虚拟的执行环境。一个虚拟的执行环境被称为一个容器(container)。可以为容器绑定特定的cpu和memory节点,分配特定比例的cpu时间、IO时间,限制可以使用的内存大小(包括内存和是swap空间),提供device访问控制,提供独立的namespace(网络、pid、ipc、mnt、uts)。
1312 0
LXC (Linux 虚拟环境)简单介绍
|
SQL 缓存 关系型数据库
Mysql跨库操作
Mysql跨库操作
366 0
|
数据采集 XML 缓存
心得经验总结:爬虫(爬虫原理与数据抓取)
心得经验总结:爬虫(爬虫原理与数据抓取)
218 0
|
移动开发 前端开发 数据可视化
一份小白前端可视化学习指南——附思维导图
一份小白前端可视化学习指南——附思维导图 前言 因为群里粉丝一直要求我写一篇「可视化入门指南」,今天他来了。其实说起前端可视化,大家所能想到的就是各种图表,大屏。这种看着贼炫酷,而笔者呢工作也一直从事3D前端开发工作,慢慢对图形产生了兴趣。但是呢一直做的是三维的东西,没搞过二维的。大概是2月前开始学习2D的一些东西,然后并写了一些文章,效果还不错。所以我就写一些经验之谈,大佬勿喷。我大概从4个方面去讲我是怎么学习的 「可视化不得不掌握的数学基础」 「svg」方面的学习 「canvas」方面的学习 「可视化中」不得不掌握的「图形算法」 读完本篇文章,你可以大概知道我该怎么去学,需要学什
一份小白前端可视化学习指南——附思维导图
|
存储 NoSQL Linux
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
本篇文章重点详细地写了Linux进程信号的知识点:Linux进程信号的概念、信号产生的方式、信号传递和信号阻塞的原理、信号捕捉的方式、内核态、用户态、可重入函数的概念、volatile理解等等。
Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号
|
IDE 算法 自动驾驶
一文搞懂CAN和CAN FD总线协议
这篇文章是将一文搞懂CAN总线协议帧格式和一文搞懂CAN FD总线协议帧格式两篇文章的整合,方便各位朋友学习和查阅。
|
Linux
LINUX下载编译libks
LINUX下载编译libks
289 0
|
存储 JSON Oracle
【网安神器篇】——hydra爆破工具
今天给大家分享的神兵利器是一款爆破工具——hydra
796 0
【网安神器篇】——hydra爆破工具