ECMAScript最新进展汇总

ECMAScript 最新进展汇总!

2023 年 7 月 11 日 - 7 月 13 日,第 97 次 TC39 会议在挪威举行,下面就来看看在这次会议中哪些 ECMAScript 提案取得了新进展吧!

TC39 是一个推动 JavaScript 发展的技术委员会,由各个主流浏览器厂商的代表构成,其主要工作就是制定 ECMAScript 标准。TC39 每两个月举行一次会议。对于新提案,从提出到最后被纳入 ECMAScript 新特性,TC39 的规范中分为五步:

  • Stage 0(strawman),任何TC39的成员都可以提交。
  • Stage 1(proposal),进入此阶段就意味着这一提案被认为是正式的了,需要对此提案的场景与API进行详尽的描述。
  • Stage 2(draft),这一阶段的提案如果能最终进入到标准,那么在之后的阶段都不会有太大的变化,因为理论上只接受增量修改。
  • Stage 3(candidate),这一阶段的提案只有在遇到了重大问题才会修改,规范文档需要被全面的完成。
  • Stage 4(finished),这一阶段的提案将会被纳入到ES每年发布的规范之中。

Stage 3

  • 数组分组
    • 提案[1] 用于简化数组(和可迭代对象)中的分组操作。数组分组是一种非常常见的操作,其将相似的数据组合成组允许开发者计算更高阶的数据集。
const array = [1, 2, 3, 4, 5];

// Object.groupBy 根据任意键对元素进行分组,这里通过奇偶数对元素进行分组。
Object.groupBy(array, (num, index) => {
  return num % 2 === 0 ? 'even': 'odd';
});
// =>  { odd: [1, 3, 5], even: [2, 4] }

// Map.groupBy 返回一个 Map 对象,方便使用对象键进行分组。
const odd  = { odd: true };
const even = { even: true };
Map.groupBy(array, (num, index) => {
  return num % 2 === 0 ? even: odd;
});
// =>  Map { {odd: true}: [1, 3, 5], {even: true}: [2, 4] }

该提案提供了两个方法:Object.groupByMap.groupBy。前者返回一个没有原型的对象,可以方便地进行解构操作,并且可以防止与全局 Object 属性发生意外冲突。后者返回一个普通的 Map 实例,可以对复杂键类型进行分组(比如复合键或元组)。

  • Promise.withResolvers
    • 当手动创建一个 Promise 时,用户必须传递一个执行器回调函数,该函数接受两个参数:

      • resolve 函数,用于触发 Promise 的解决;
      • reject 函数,用于触发 Promise 的拒绝。

      如果回调函数可以嵌入调用一个最终触发解决或拒绝的异步函数(例如注册事件监听器),则这种方式可以很好地工作。

      const promise = new Promise((resolve, reject) => {
        asyncRequest(config, response => {
          const buffer = [];
          response.on('data', data => buffer.push(data));
          response.on('end', () => resolve(buffer));
          response.on('error', reason => reject(reason));
        });
      });
      

      然而,通常开发人员希望在实例化 Promise 后配置其解决和拒绝行为。目前,这需要一个繁琐的解决方法,从回调范围中提取 resolvereject 函数:

      let resolve, reject;
      const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
      });
      asyncRequest(config, response => {
        const buffer = [];
        response.on('callback-request', id => {
          promise.then(data => callback(id, data));
        });
        response.on('data', data => buffer.push(data));
        response.on('end', () => resolve(buffer));
        response.on('error', reason => reject(reason));
      });
      

      开发人员可能还有其他要求,需要将 resolve/reject 传递给多个调用方,因此必须以这种方式实现:

      let resolve = () => { };
      let reject = () => { };
      
      function request(type, message) {
        if (socket) {
          const promise = new Promise((res, rej) => {
            resolve = res;
            reject = rej;
          });
          socket.emit(type, message);
          return promise;
        }
      
        return Promise.reject(new Error('Socket unavailable'));
      }
      
      socket.on('response', response => {
        if (response.status === 200) {
          resolve(response);
        }
        else {
          reject(new Error(response));
        }
      });
      
      socket.on('error', err => {
        reject(err);
      });
      

      Promise.withResolvers[2] 提案简单地在 Promise 构造函数中添加了一个静态方法,暂时称为withResolvers,该方法返回一个 Promise,并方便地公开其解决和拒绝函数。

      const { promise, resolve, reject } = Promise.withResolvers();
      
  • 源阶段导入
    • 无论是对于 JavaScript 还是 WebAssembly,都需要能够更紧密地定制模块的加载、链接和执行,超出了标准的宿主执行模型。

      • 对于 JavaScript,创建自定义加载器需要一种模块源类型,以便共享宿主的解析、执行、安全性和缓存语义。
      • 对于 WebAssembly,WebAssembly 模块的导入和导出通常需要进行自定义的检查和封装,以便正确设置,这通常需要手动的获取和实例化工作,在当前的宿主 ESM 集成提案中没有提供相应支持。

      通过将语法模块源导入支持作为新的导入阶段,可以创建一个基础机制,将模块的静态、安全性和工具化优势从 ESM 集成扩展到这些动态实例化用例。

      提案[3]允许ES模块从主机提供的编译后的模块源的反映表达式进行导入:

      import source x from "<specifier>";
      

      仅支持上述形式的导入,不支持命名导出和未绑定声明。

      动态形式使用 import.

      const x = await import.source("<specifier>");
      

      通过将阶段作为显式语法的一部分,可以在静态上下文中静态区分全动态导入和仅用于源的导入(无需处理依赖项)。

  • 处理时间区域规范化的变化
    • ECMAScript中的时间区域依赖于IANA时区数据库(TZDB)的标识符,如America/Los_Angeles或Asia/Tokyo。该提案旨在改善开发人员在TZDB中更改时间区域的规范标识符(例如从Europe/KievEurope/Kyiv)时的开发体验。
    减少实现之间以及实现与规范之间的差异
    1. 已完成 - 简化处理时区标识符的抽象操作。
    2. 已完成 - 澄清规范以防止更多的分歧。
    3. 在 Temporal 广泛采用之前,帮助V8和WebKit更新13个过时的规范标识(如Asia/Calcutta,Europe/Kiev和Asia/Saigon),以免出现问题。
    4. 制定规范文本以减少实现之间的分歧。这一步需要在实现者和TG2(ECMA-402团队)之间找到共同点,讨论规范化应该如何工作。
    减少标准化变化的影响
    1. 避免对链接进行可观察的跟随。如果标准化变化不会影响现有代码,那么未来的标准化变化就不太可能破坏Web。由于标准化是实现定义的,这个变化(或许会、也许不会;需要进一步研究)在Temporal第4阶段之后发布可能是安全的,但最好不要等太久。

      Temporal.TimeZone.from('Asia/Calcutta');
      // => Asia/Kolkata(Firefox上当前的Temporal行为)
      // => Asia/Calcutta(建议:在将标识符返回给调用方时,不要遵循链接)
      
    2. 添加Temporal.TimeZone.prototype.equals方法。由于(5)会在创建TimeZone对象时停止标准化标识符,因此有一个直观的方法来判断两个 TimeZone 对象是否表示相同的时区。

      // 更人性化的标准化相等性测试
      Temporal.TimeZone.from('Asia/Calcutta').equals('Asia/Kolkata');
      // => true
      

    Stage 2

    Time Zone Canonicalization[4]

    ​ JavaScript应用程序可能会变得非常庞大,以至于即使加载它们的初始化脚本,执行起来也会产生显著 的性能开销。通常,这种情况发生在应用程序的生命周期较晚的阶段,往往需要进行大规模的改动以提 高性能。加载性能是一个重要的改进领域,涉及预加载技术以避免瀑布效应,并使用动态导入进行模块 的惰性加载。

    ​ 尽管使用了这些技术解决了加载性能问题,但代码本身的编写方式仍会导致执行性能开销和CPU瓶颈在 初始化过程中出现。

    ​ 该提案[5]是引入一种新的导入语法形式,它将始终返回一个命名空间对象。在使用时,模块及其依赖 项不会被执行,但会完全加载到可以执行的状态,然后才会认为模块图已加载完成。只有当访问该模块 的属性时,才会执行相应的操作。

    ​ 该API将使用以下语法:

    // 或使用自定义关键字: 
    import defer * as yNamespace from "y";
    

    Stage 1

    DataView get/set Uint8Clamped 方法

    现在只有其中 10 个具有DataView的 get/set 方法。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lzTBEHeP-1691236380594)(C:\Users\Admin\Desktop\csdn\dataView.png)]

    ​ 该提案[6]旨在添加DataView.prototype.getUint8ClampedDataView.prototype.setUint8Clamped方法。

    • getUint8Clamped(offset: number): number:从指定的偏移量读取一个8位无符号整数(Uint8Clamped)值,并返回该值。
    • setUint8Clamped(offset: number, value: number): void:将一个8位无符号整数(Uint8Clamped)值写入到指定的偏移量。
    可选链赋值

    提案[7]建议在赋值运算符左侧添加对可选链的支持:a?.b = c。在实际开发中,经常需要对对象的属性进行赋值,但前提是该对象确实存在。

    通常的做法是使用if语句来保护赋值操作:

    if (obj) {
      obj.prop = value;
    }
    

    新语法和现有语法对比如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ufis3b8M-1691236380595)(C:\Users\Admin\Desktop\csdn\语法对比.png)]

相关链接

[1]提案: https://github.com/tc39/proposal-array-grouping

[2]Promise.withResolvers: https://github.com/tc39/proposal-promise-with-resolvers

[3] 提案: https://github.com/tc39/proposal-source-phase-imports

[4]Time Zone Canonicalization: https://github.com/tc39/proposal-canonical-tz

[5]提案: https://github.com/tc39/proposal-defer-import-eval

[6]提案: https://github.com/tc39/proposal-dataview-get-set-uint8clamped

mports*

[4]Time Zone Canonicalization: https://github.com/tc39/proposal-canonical-tz

[5]提案: https://github.com/tc39/proposal-defer-import-eval

[6]提案: https://github.com/tc39/proposal-dataview-get-set-uint8clamped

[7]提案: https://github.com/tc39/proposal-optional-chaining-assignment

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值