Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

精读《TC39, ECMAScript, and the Future of JavaScript》 #21

Closed
ascoders opened this issue Jul 2, 2017 · 12 comments
Closed

精读《TC39, ECMAScript, and the Future of JavaScript》 #21

ascoders opened this issue Jul 2, 2017 · 12 comments

Comments

@ascoders
Copy link
Owner

ascoders commented Jul 2, 2017

搞清楚 TC39, ECMAScript 之间的关系,以及 js 最近又有什么新动静了。

@ascoders ascoders mentioned this issue Jul 2, 2017
65 tasks
@linhuiw
Copy link
Contributor

linhuiw commented Jul 2, 2017

本期精读文章地址: https://ponyfoo.com/articles/tc39-ecmascript-proposals-future-of-javascript

@huxiaoyun
Copy link
Contributor

huxiaoyun commented Jul 2, 2017

TC39是什么?包括哪些人?

一个推动JavaScript发展的委员会,由各个主流浏览器厂商的代表构成。

为什么会出现这样一个组织?

从标准到落地是一个漫长的过程,相信大家上次阅读web components就能体会到标准到浏览器支持是一个漫长的过程。

TC39 这群人主要的工作是什么?

制定ECMAScript标准,标准生成的流程,并实现。

标准的流程是什么样的?

包括五个步骤:

  • stage0 strawman
    任何讨论、想法、改变或者还没加到提案的特性都在这个阶段。只有TC39成员可以提交。

  • stage1 proposal
    (1)产出一个正式的提案。
    (2)发现潜在的问题,例如与其他特性的关系,实现难题。
    (3)提案包括详细的API描述,使用例子,以及关于相关的语义和算法。

  • stage2 draft
    (1)提供一个初始的草案规范,与最终标准中包含的特性不会有太大差别。草案之后,原则上只接受增量修改。
    (2)开始实验如何实现,实现形式包括polyfill, 实现引擎(提供草案执行本地支持),或者编译转换(例如babel)

  • stage3 candidate
    (1)候选阶段,获得具体实现和用户的反馈。此后,只有在实现和使用过程中出现了重大问题才会修改。
    (1)规范文档必须是完整的,评审人和ECMAScript的编辑要在规范上签字。
    (2)至少要在一个浏览器中实现,提供polyfill或者babel插件。

  • stage4 finished
    (1)已经准备就绪,该特性会出现在下个版本的ECMAScript规范之中。。
    (2)需要通过有2个独立的实现并通过验收测试,以获取使用过程中的重要实践经验。

目前每个stage 包含什么特性呢?

  • stage0 strawman
  1. cancellation tokens
  2. Zones as the ones originally hailed by the Angular team

https://github.com/tc39/proposals/blob/master/stage-0-proposals.md

额外注意的是: Cancellation API 已经成熟要录入到 stage1,它提供程序主动终止 asyn 操作的API。

  • stage1 proposal
  1. Observalbe
  2. do expresions
  3. generator
  4. arrow functions
  5. Promise.try
  • stage2 draft
  1. public class fields
  2. private class fields
  3. decorators
  4. Promise#finally
  • stage3 candidate
  1. object rest and spread
  2. asynchronous iteration
  3. import()
  4. better Unicode support for regular expressions
  • stage4 finished
  1. async functions - fetch
  2. Array#includes - array.indexOf() 的另一种实现
  3. exponentiation operator

一般可以去哪里查看TC39标准的进程呢?

stage0 的提案 https://github.com/tc39/proposals/blob/master/stage-0-proposals.md
stage1 - 4 的提案 https://github.com/tc39/proposals

我们怎么在程序中应用这些新特性呢?

babel的插件 babel-presets-stage-0 babel-presets-stage-1 babel-presets-stage-2 babel-presets-stage-3 babel-presets-stage-4

@ascoders
Copy link
Owner Author

ascoders commented Jul 4, 2017

粗看了一遍,搞明白 TC39,ECMA 与 stage0~4 之间的关系了。后续会整理出来给懒人阅读。

文章末尾提到了对 babel webpack prepack 的积极看法,我也对这些新东西持续关注中,不过本次精读主要会讨论一下全套 stage0~stage4 的提案,纯属个人看法,以后若被打脸,麻烦忘了这期精读。。

@monkingxue
Copy link

今天看到 stage0 又新增一员——Pattern Matching Syntax,突然兴奋,这绝对是我最期待的语法之一了。当然也不能高兴太早,按照这期文章中的说法,stage0 还只是 “strawman”,镜中花水中月。

当然从 README.md 中不难发现,模式匹配是有 Object rest 的,而这个语法现在是在 stage3,已经有了 babel 的 Plugin,不太清楚这种依赖性的提案会怎么处理,不过如果要等到 Object rest 并入 master 才会去允许模式匹配提案的进行的话,那未免有点扫兴了(摊手

@ascoders
Copy link
Owner Author

ascoders commented Jul 6, 2017

Stage 4 大家庭

Array.prototype.includes

assert([1, 2, 3].includes(2) === true);
assert([1, 2, 3].includes(4) === false);

assert([1, 2, NaN].includes(NaN) === true);

assert([1, 2, -0].includes(+0) === true);
assert([1, 2, +0].includes(-0) === true);

assert(["a", "b", "c"].includes("a") === true);
assert(["a", "b", "c"].includes("a", 1) === false);

这个 api 很方便,没有悬念的进入了草案中。

曾争议过是否使用 Array.prototype.contains,但由于 不兼容因素 而换成了 includes。

Exponentiation operator

// x ** y

let squared = 2 ** 2;
// same as: 2 * 2

let cubed = 2 ** 3;
// same as: 2 * 2 * 2

列表中进入了 stage4,但其 git 仓库 readme 还停留在 stage3。。

虽然已经有 Math.pow 了,但由于其他语言都支持此方式,js 也就支持了。

Object.values/Object.entries

Object.values({
	a: 1,
	b: 2,
	c: Symbol(),
}) // [1, 2, Symbol()]

Object.entries({
	a: 1,
	b: 2,
	c: Symbol(),
}) // [["a", 1], ["b", 2], ["c", Symbol()]]

也没有什么争议,Object.keys 都有了,获取 values、entries 也是合理的。

TC39 会议中有争辩过为何不返回迭代器,原因挺有意思,因为 Object.keys 返回的是数组,所以这两个 api 还是与老大哥统一吧。

String.prototype.padStart / String.prototype.padEnd

"foo".padStart(5, "bar") // bafoo
"foo".padEnd(5, "bar") // fooba

解决了字符串补齐需求,很棒!

Object.getOwnPropertyDescriptors

Object.getOwnPropertyDescriptors({ a: 1})
// { a: {
// 	  configurable: true,
// 	  enumberable: true,
// 	  value: 1,
//	  writable: true
// } }

特别是 babel 与 typescript 处理 class property decorator 方式不同的时候(typescript 处理得更成熟一些),会导致 babel 处理装饰器时,成员变量不设置默认值时,configurable 默认为 false,通过这个函数检查变量的配置很方便。

Trailing commas in function parameter lists and calls

function clownPuppiesEverywhere(
   param1,
   param2, // Next parameter that's added only has to add a new line, not modify this line
 ) { /* ... */ }

js 终于原生支持了,以前不支持的时候多加逗号还会报错,需要预编译工具删除最后一个逗号,现在终于名正言顺了。

Async functions

这个不用多说了,都说好用。

Shared memory and atomics

这是 ECMAScript 共享内存与 Atomics 的规范,涉及内容非常多,主要涉及到 asm.js。

asm.js 是一种性能解决方案,比如可以定义一个精确的 64k 堆:

var heap = new ArrayBuffer( 0x10000 )

Lifting template literal restriction

styled.div`
  background-color: red;
`

styled.div = text => {} 就可以处理了,目前使用最多在 styled-components 库里,这种场景还是蛮方便的。

@jasonslyvia
Copy link
Contributor

padStart padEnd 早点写入规范说不定就没当年的 leftpad 事件了

@DanielWLam
Copy link

cool

@ascoders
Copy link
Owner Author

ascoders commented Jul 6, 2017

Stage 3 大家庭

Function.prototype.toString revision

对函数的 toString 规则进行了修改:http://tc39.github.io/Function-prototype-toString-revision/#sec-function.prototype.tostring

当调用内置函数或 .bind 后函数,toString 方法会返回 NativeFunction

global

为 ECMAScript 规范添加 global 变量,同构代码再也不用这么写了:

var getGlobal = function () {
	// the only reliable means to get the global object is
	// `Function('return this')()`
	// However, this causes CSP violations in Chrome apps.
	if (typeof self !== 'undefined') { return self; }
	if (typeof window !== 'undefined') { return window; }
	if (typeof global !== 'undefined') { return global; }
	throw new Error('unable to locate global object');
};

虽然前端环境与 nodejs 区别很大,但既然提案进入了 stage3,说明大家非常关注 js 整体的生态,只要整体方向良性发展,相信不久将会进入 stage4。

Rest/Spread Properties

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }

不得不说,非常常用,而且 babeljsTransformtypescript 均支持,感觉很快会进入 stage4.

Asynchronous Iteration

const { value, done } = syncIterator.next();

asyncIterator.next().then(({ value, done }) => /* ... */);
for await (const line of readLines(filePath)) {
  console.log(line);
}
async function* readLines(path) {
  let file = await fileOpen(path);

  try {
    while (!file.EOF) {
      yield await file.readLine();
    }
  } finally {
    await file.close();
  }
}

异步迭代器实现了 async await 与 generator 的结合。
然而 async await 是使用 generator 的语法糖,generator 也可以通过 switch 等流程控制函数模拟。更重要的是异步在 generator 中本身就可以实现,我在《Callback Promise Generator Async-Await 和异常处理的演进》 文章中提过。

语法的修改一定不能为了方便(在 ECMAScript 中可能出现),但这种混杂的方式容易让人混淆 await 与 generator 之间的关系,是否进入 stage4 还需仔细斟酌。

import()

import(`./section-modules/${link.dataset.entryModule}.js`)
    .then(module => {
      module.loadPageInto(main);
    })
    .catch(err => {
      main.textContent = err.message;
    });

这个提案主要增加了函数调用版的 import,而 webpack 等构建工具也在积极实现此规范,并作为动态加载的最佳范例。希望这种“官方 Amd”可以早日加入草案。

RegExp Lookbehind Assertions

javascript 正则表达式一直不支持后行断言,不过现在已经进入 stage3,相信不久会进入 stage4.

前向断言:

/\d+(?=%)/.exec("100% of US presidents have been male") // ["100"]
/\d+(?!%)/.exec("that’s all 44 of them") // ["44"]

后向断言:

/(?<=\$)\d+/.exec("Benjamin Franklin is on the $100 bill")  // ["100"]
/(?<!\$)\d+/.exec("it’s is worth about €90")                // ["90"]

后向断言会获取某个字符后面跟的内容,在获取美刀等货币单位上有很大用途。chrome 可以使用 chrome.exe --js-flags="--harmony-regexp-lookbehind" 命令开启。

RegExp Unicode Property Escapes

const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π');
// → true

以上 π 字符是一个希腊字符,通过指定 \p{Script=Greek} 就可以匹配这个字符了!

虽然可以通过引用希腊字符(或者其他编码)表做正则处理,当每当更新表时,更新起来会非常麻烦,不如让浏览器原生支持 \p{UnicodePropertyName=UnicodePropertyValue} 的正则语法,帮助开发人员解决这个烦恼。

RegExp named capture groups

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
let result = re.exec('2015-01-02');
// result.groups.year === '2015';
// result.groups.month === '01';
// result.groups.day === '02';

// result[0] === '2015-01-02';
// result[1] === '2015';
// result[2] === '01';
// result[3] === '02';
let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
console.log(`one: ${one}, two: ${two}`);  // prints one: foo, two: bar

同时,还支持 反向引用能力,可以通过 \k<name> 的语法,在正则中表示同一种匹配类型,这个和 ts 范型很像:

let duplicate = /^(?<half>.*).\k<half>$/u;
duplicate.test('a*b'); // false
duplicate.test('a*a'); // true

总体来看非常给力,毫无意义的下标也是正则反人类的原因之一,这个提案通过的话,正则会变得更加可读。

s (dotAll) flag for regular expressions

/foo.bar/s.test('foo\nbar');
// → true

通过添加了新的标识符 /s,表示 . 这个标志可以匹配任何值。原因是觉得现在正则的做法比较反人类:

/foo[^]bar/.test('foo\nbar');
// → true
/foo[\s\S]bar/.test('foo\nbar');
// → true

从保守派角度来看,可能因为掌握了 [^] [\s\S] 这种奇技淫巧而沾沾自喜,借此提高正则的门槛,让初学者“看不懂”,而高级语言的第一要义是可读性,RegExp Unicode Property EscapesRegExp named capture groups 进入草案就是表明了对正则语义化改进的决心,相信这个提案也会被采纳。

Legacy RegExp features in JavaScript

该提案主要针对 RegExp 遗留的静态属性进行梳理。平时很少接触,希望了解的人解读一下。

@ascoders
Copy link
Owner Author

ascoders commented Jul 7, 2017

Stage2 大家庭

function.sent metaproperty

generator 的第一个 .next 参数会被抛弃,因为第一次 next 没有对应上任何 yield,如下代码就会产生疑惑:

function *adder(total=0) {
   let increment=1;
   while (true) {
       switch (request = yield total += increment) {
          case undefined: break;
          case "done": return total;
          default: increment = Number(request);
       }
   }
}

let tally = adder();
tally.next(0.1); // argument will be ignored
tally.next(0.1);
tally.next(0.1);
let last=tally.next("done");
console.log(last.value);  //1.2 instead of 0.3

当引入 function.sent 后,可以接收来自 next 的传值,包括初始传值

function *adder(total=0) {
   let increment=1;
   do {
       switch (request = function.sent){
          case undefined: break;
          case "done": return total;
          default: increment = Number(request);
       }
       yield total += increment;
   } while (true)
}

let tally = adder();
tally.next(0.1); // argument no longer ignored
tally.next(0.1);
tally.next(0.1);
let last=tally.next("done");
console.log(last.value);  //0.3

这是个很棒的特性,也不存在语意兼容问题,但 api 还是比较怪,而且自此 yield 接收参数也变得没有意义,况且如今 async await 逐渐成为主流,这种修正没有强烈刚需。而且 yield 的语意本身没有错误,这个提案比较危险。

String.prototype.{trimStart,trimEnd}

既然 padStartpadEnd 都进入了 stage4,trimStart trimEnd 这两个 api 也非常常用,而且从 ES5 将 String.prototype.trim 引入了标准来看,这两个非常有望晋升到 stage3。

Class Fields

class Counter extends HTMLElement {
  x = 0;
  #y = 1;
}

类成员变量,有了它 js 就完整了。虽然觉得似有变量符号很难看,但成员变量绝对是非常有用的语法,在 react 中已经很常用了:

class Todo extends React.Component {
  state = { //.. }
}

Promise.prototype.finally

就像 try/catch/finally 一样,try return 了都能执行 finally,是非常方便的,对 promise 来说也是如此,bluebird Q 等库已经实现了此功能。

但是库实现不足以使其纳入标准,只有当这些需求足够常用和通用时才会考虑。第三方库可能从竞争力角度考虑,多支持一种功能、少些一行代码就是多一份筹码,但语言规范是不能在乎这些的。

Class and Property Decorators

类级别的装饰器已经进入 stage2 了,但现代前端开发中已经非常常用,很可能会进一步进入 stage3.

如果这个提案被废弃,那么大部分现代 js 代码将面临大量使用不存在语法的窘境。不过乐观的是,目前还找不到更好的装饰器替代方案,而在 python 中也存在装饰器模式可以参考。

Intl.Segmenter

// Create a segmenter in your locale
let segmenter = new Intl.Segmenter("fr", {granularity: "word"});

// Get an iterator over a string
let iterator = segmenter.segment("Ceci n'est pas une pipe");

// Iterate over it!
for (let {segment, breakType} of iterator) {
  console.log(`segment: ${segment} breakType: ${breakType}`);
  break;
}

// logs the following to the console:
// segment: Ceci breakType: letter

Intl.Segmenter 可以帮助分析单词断句分析,可能在 nlp 领域比较有用,在文本编辑器自动选中功能中也很有用。

虽然不是刚需,但 js 作为网页交互的语言,确实需要解决分析用户输入的问题。

Arbitrary-precision Integers

新增了基本类型:整数类型,以及 Integer api 与字面语法 1234n。

目前 js 使用 64 位浮点数处理所有计算,直接导致了运算效率低下,这个提案弥补了 js 的计算缺点,希望可以早日进入草案。

提案名称由 Integer 改为 BigInt。

import.meta

提出了使用 import.meta 获取当前模块的域信息。类比 nodejs 存在 __dirname 等信息标志当前脚本信息,通过浏览器加载的模块也应当拥有这种能力。

目前 js 可以通过如下方式获取脚本信息:

const theOption = document.currentScript.dataset.option;

这样污染了全局变量,脚本信息应当存储在脚本作用域中,因此提案希望将脚本信息存储在脚本的 import.meta 变量中,因此可以这么使用:

(async () => {
  const response = await fetch(new URL("../hamsters.jpg", import.meta.url));
  const blob = await response.blob();

  const size = import.meta.scriptElement.dataset.size || 300;

  const image = new Image();
  image.src = URL.createObjectURL(blob);
  image.width = image.height = size;

  document.body.appendChild(image);
})();

@huxiaoyun
Copy link
Contributor

重点关注了 stage0 的 cancellation API, 这个特性我感觉会升级的特别快...

为啥会出现这个api

  1. 取消异步操作,常见以下操作情景:1) 异步方法 2)fetch 请求 3)与浏览器后端交互如 webworker forked processes 4) 长时间操作 如 动画
  2. 和 nodejs IOT 等其他环境运行的JS API 保持一致

关键的类

  • CancellationTokenSource
    class CancellationTokenSource { constructor(linkedTokens?: Iterable<CancellationToken>); readonly token: CancellationToken; cancel(): void; close(): void; }
  • CancellationToken
    class CancellationToken { static readonly none: CancellationToken; // 永远不取消 static readonly canceled: CancellationToken; // 已经取消 readonly cancellationRequested: boolean; // 标志位,是否取消 readonly canBeCanceled: boolean; // 是否可以取消 throwIfCancellationRequested(): void; register(callback: () => void): { unregister(): void; }; }
  • CancelError
    class CancelError extends Error { constructor(message?: string); }

尝鲜方法和例子

@ascoders
Copy link
Owner Author

ascoders commented Jul 7, 2017

Stage1 大家庭

Date.parse fallback semantics

通过字符串格式化日期一直是跨浏览器的痛点,本提案希望通过新增 Date.parse 标准完成这个功能。

"The function first attempts to parse the format of the String according to the rules
(including extended years) called out in Date Time String Format (20.3.1.16). If the
String does not conform to that format the function may fall back to any
implementation-specific heuristics or implementation-specific date formats."

正如提案所说,“如果字符串不满足 ISO 8601 格式,可以返回你想返回的任何值” 这样迷惑开发者是没有任何意义的,这样只会让开发者越来越不相信 js 是跨平台的语言。

这么重要的规范居然才 stage1,必须要顶上去。

export * as ns from "mod"; statements

export * as someIdentifier from "someModule";

很方便的 api,很多时候希望导出某个模块的全部接口,又不希望命名冲突,可以少写一行 import。

export v from "mod"; statements

这个提案与 export * as ns from "mod"; statements
冲突了,感觉 export * as ns from "mod"; statements
提案更清晰一些。

Observable

可观察类型可以从 dom 事件、轮询等触发事件中创建监听并订阅:

function listen(element, eventName) {
    return new Observable(observer => {
        // Create an event handler which sends data to the sink
        let handler = event => observer.next(event);

        // Attach the event handler
        element.addEventListener(eventName, handler, true);

        // Return a cleanup function which will cancel the event stream
        return () => {
            // Detach the event handler from the element
            element.removeEventListener(eventName, handler, true);
        };
    });
}

// Return an observable of special key down commands
function commandKeys(element) {
    let keyCommands = { "38": "up", "40": "down" };

    return listen(element, "keydown")
        .filter(event => event.keyCode in keyCommands)
        .map(event => keyCommands[event.keyCode])
}

let subscription = commandKeys(inputElement).subscribe({
    next(val) { console.log("Received key command: " + val) },
    error(err) { console.log("Received an error: " + err) },
    complete() { console.log("Stream complete") },
});

这个名字和 Object.observe 很像,不过没什么关系。该功能已经被 RxJSXStream 等库实现。

String#matchAll

目前正则表达式想要匹配全部的语法不够语义化,提案希望通过 matchAll 返回迭代器来遍历匹配结果,很赞!

现在匹配全部只能使用 while ((result = patt.exec(str)) != null) 这种方式遍历,不优雅。

WeakRefs

弱引用,提案地址文档:https://github.com/tc39/proposal-weakrefs/blob/master/specs/Weak%20References%20for%20EcmaScript.pdf

有点像 OC 的弱引用,当对象被释放时,当前持有弱引用的对象也会被 GC 回收,但似乎还没有开始讨论,js 越来越底层了?

Frozen Realms

增强了 Realms 提案,利用不可变结构,实现结构共享。

Math Extensions

Math 函数的拓展包含的函数:https://rwaldron.github.io/proposal-math-extensions/

这个函数拓展很给力,特别是设计游戏,计算角度的时候:

Math.DEG_PER_RAD // Math.PI / 180

Math.DEG_PER_RAD 是一种单位,让角度可以用 0~360 为周期的数字表示,比如射击子弹时的角度、或者做可视化时都非常有用,类比 css 中的:transform: rotate(180deg);

of and from on collection constructors

该提案设计了 Set、Map 类型的 of from 方法,具体见此:https://tc39.github.io/proposal-setmap-offrom/

问题由于:

Reflect.construct(Array, [1,2,3]) // [1,2,3]
Reflect.construct(Set, [1,2,3]) // Uncaught TypeError: undefined is not a function

因为 Set 接收的参数是数组,而 construct 会调用 CreateListFromArrayLike 将参数打平,变成了 new Set(1, 2, 3) 传入,实际上是语法错误的,因此作者提议新增下 Set、Map 的 of from 方法。

Set、Map 在国内环境用的比较少,也很少有人计较这个问题,不过从技术角度来看,确实需要修复。。

Generator arrow functions (=>*)

还是挺有必要的,毕竟都出箭头函数了,也要支持一下箭头函数的 generator 语法。

Promise.try

同理,各大库都有实现,好处是所有错误都可以通过 .catch 捕获,而不用担心同步、异步错误的抛出。

Null Propagation

超级有用,看代码就知道了:

const firstName = message.body?.user?.firstName || 'default'

该功能完全等同:

const firstName = 
	()message && 
	message.body && 
	message.body.user &&
	message.body.user.firstName) || 'default'

希望立刻进入 stage4.

Math.signbit: IEEE-754 sign bit

当值为 负数 或 -0 时返回 true。由于 Math.sign 不区分 +0 与 -0,因此提案建议增加此函数,而且此函数在 c、c++、go语言都有实现。

Error stacks

提案建议将 Error.prototype.stack 作为标准,这对错误上报与分析特别有用,强烈支持。

do expressions

return (
  <nav>
    <Home />
    {
      do {
        if (loggedIn) {
          <LogoutButton />
        } else {
          <LoginButton />
        }
      }
    }
  </nav>
)

jsx 再也不用写得超长了,styled-components 中被诟病的分支判断难以阅读的问题也会烟消云散,因为我们有 do!

Realms

let realm = new Realm();

let outerGlobal = window;
let innerGlobal = realm.global;

let f = realm.evalScript("(function() { return 17 })");

f() === 17 // true

Reflect.getPrototypeOf(f) === outerGlobal.Function.prototype // false
Reflect.getPrototypeOf(f) === innerGlobal.Function.prototype // true

Realms 提供了 global 环境的隔离,eval 执行代码时不再会污染全局,简直是测试的福利,脑洞很大。

Temporal

Date 类似,但功能更强:

var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, options);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59, options);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59, 123);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59, 123, options);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59, 123, 456789);
var ldt = new temporal.LocalDateTime(2017, 12, 31, 23, 59, 59, 123, 456789, options);

// add/subtract time  (Dec 31 2017 23:00 + 2h = Jan 1 2018 01:00)
var addHours = new temporal.LocalDateTime(2017, 12, 31, 23, 00).add(2, 'hours');

// add/subtract months  (Mar 31 - 1M = Feb 28)
var addMonths = new temporal.LocalDateTime(2017,03,31).subtract(1, 'months'); 

// add/subtract years  (Feb 29 2020 - 1Y = Feb 28 2019)
var subtractYears = new temporal.LocalDateTime(2020, 02, 29).subtract(1, 'years');

还自带时区转换 api 等等,如果进入草案,可以放弃 moment 这个重量级库了。

Float16 on TypedArrays, DataView, Math.hfround

由于大多数 WebGL 纹理需要半精度以上的浮点数计算,推荐了 4 个 api:

  • Float16Array
  • DataView.prototype.getFloat16
  • DataView.prototype.setFloat16
  • Math.hfround(x)

Atomics.waitNonblocking

var sab = new SharedArrayBuffer(4096);
var ia = new Int32Array(sab);
ia[37] = 0x1337;
test1();

function test1() {
  Atomics.waitNonblocking(ia, 37, 0x1337, 1000).then(function (r) { console.log("Resolved: " + r); test2(); });
}
var code = `
var ia = null;
onmessage = function (ev) {
  if (!ia) {
    console.log("Aux worker is running");
    ia = new Int32Array(ev.data);
  }
  console.log("Aux worker is sleeping for a little bit");
  setTimeout(function () { console.log("Aux worker is waking"); Atomics.wake(ia, 37); }, 1000);
}`;
function test2() {
  var w = new Worker("data:application/javascript," + encodeURIComponent(code));
  w.postMessage(sab);
  Atomics.waitNonblocking(ia, 37, 0x1337).then(function (r) { console.log("Resolved: " + r); test3(w); });
}
function test3(w) {
  w.postMessage(false);
  Atomics.waitNonblocking(ia, 37, 0x1337).then(function (r) { console.log("Resolved 1: " + r); });
  Atomics.waitNonblocking(ia, 37, 0x1337).then(function (r) { console.log("Resolved 2: " + r); });
  Atomics.waitNonblocking(ia, 37, 0x1337).then(function (r) { console.log("Resolved 3: " + r); });
  
}

该 api 可以在多线程操作中,有顺序的操作同一个内存地址,如上代码变量 ia 虽然在多线程中执行,但每个线程都会等资源释放后再继续执行。

Numeric separators

1_000_000_000           // Ah, so a billion
101_475_938.38          // And this is hundreds of millions

let fee = 123_00;       // $123 (12300 cents, apparently)
let fee = 12_300;       // $12,300 (woah, that fee!)
let amount = 12345_00;  // 12,345 (1234500 cents, apparently)
let amount = 123_4500;  // 123.45 (4-fixed financial)
let amount = 1_234_500; // 1,234,500

提案希望 js 支持分隔符使大数字阅读性更好(不影响计算),很多语言都有实现,很人性化。

@ascoders ascoders closed this as completed Jul 7, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants