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)与我们讨论。

相关文章
|
8月前
|
存储 数据可视化 搜索推荐
必看!提升直播与央视对接技术细节处理效率的神器?
在视频直播行业竞争激烈的当下,高效的团队协作和个人学习能力至关重要。本文介绍了6款可视化团队协作办公软件:板栗看板、Trello、Asana、Jira、Notion和Monday.com。这些工具通过简洁直观的界面、强大的任务管理、丰富的插件生态和自动化功能,帮助团队更好地沟通、协作和学习,提升工作效率,确保直播活动顺利进行。选择合适的软件,助力团队在2025年新春各大直播活动中脱颖而出。
151 12
|
机器学习/深度学习 自然语言处理 数据可视化
分布式表示(Distributed Representation)
分布式表示(Distributed Representation)
416 2
|
12月前
|
Go C语言
golang的类型转换
【9月更文挑战第28天】本文介绍了Go语言中的基本数据类型转换,包括数值类型之间的转换及字符串与数值类型的互转,提供了具体代码示例说明如何使用如`float64(a)`和`strconv.Atoi`等方法。同时,文章还讲解了接口类型转换,包括类型断言和类型开关的使用方法,并展示了如何在运行时获取具体类型。最后,提到了指针类型转换的注意事项及其应用场景。
170 7
|
自然语言处理 算法 测试技术
【C/C++ CommonAPI入门篇】从 Franca IDL 到 C++: 深入解析汽车软件接口开发
【C/C++ CommonAPI入门篇】从 Franca IDL 到 C++: 深入解析汽车软件接口开发
734 1
|
人工智能 编解码
AI 绘画Stable Diffusion 研究(十三)SD数字人制作工具SadTlaker使用教程
AI 绘画Stable Diffusion 研究(十三)SD数字人制作工具SadTlaker使用教程
839 0
|
移动开发 前端开发 JavaScript
Web表单(Form)开发实战指南
【7月更文挑战第8天】表单(Form)是Web应用程序中不可或缺的组成部分,用于收集用户输入的数据。本指南将详细介绍HTML表单的基本结构、数据提交方式、表单验证以及如何使用JavaScript和CSS增强表单的交互性和美观性。
458 0
|
开发框架 Linux C++
Qt:强大的跨平台C++应用程序开发框架
Qt:强大的跨平台C++应用程序开发框架
450 3
虚拟节点是什么?
虚拟节点是什么?
312 1
|
JSON 数据格式
将json格式的数据快速转换为excel,使用在线工具轻松搞定
将json格式的数据快速转换为excel,使用在线工具轻松搞定
797 0
|
移动开发 小程序 JavaScript
总结10条~高级前端必知的小程序体积优化策略
我们都知道微信小程序有包体积限制,整个小程序所有分包大小不超过 20M,单个分包/主包大小不能超过 2M。然而面对业务的不断更新迭代,代码和资源会越来越多,如果不尽早规划包体积的治理,势必有一天会对业务的发展造成阻碍。所以如何在有效支持业务逻辑的同时,尽量减少资源占用,在小程序开发环境中显得尤为重要。 代码包体积是其中的一个重要方面,本文将就此进行分析与探讨。
690 0
总结10条~高级前端必知的小程序体积优化策略