作者 | 秦粤
摩登【基本释义】 [modern; fashionable] 适合现时或表现现时;时髦。
今年D2语言与框架专场,我们邀请了RxJS的Ben lesh跟我们讲他们如何重构RxJS的代码,让RxJS的库代码变的更小,更快。另外也邀请了Igalia的Ujjwal跟我们讲ES2020和ESNext ES2021。Ben给我们演示了一波现场Coding,演示他们是如何RxJS是如何思考重写和重构的。Ujjwal的演讲内容信息量很大,从TC39的运营模式到ECMAScript2020和ECMAScriptNext。我们阿里巴巴的议题Error Cause(Stage2)和Async Context(Stage 0),以及参与推进的BigDecimal(Stage 1),由于都没有进入Stage4,因此这次并没有跟大家在分享中介绍。
JavaScript作为全球最流行,支持范围最广的语言。从1996年到今天已经经历了24年。它之所以生命力如此顽强的原因之一,就是因为它是动态弱类型(免编译),而且是有官方标准。官方标准就是由著名的TC39委员会维护的ECMAScript。
我们在ben的重构和重写代码的分享中也可以看出,RxJS摈弃了很多对旧的JS语法的支持,尤其是ES5的。不知道同学们有没有想到一个问题,JS的官方标准都已经ES2020,为什么我们还要关注ES5,也就是ECMAScript2009?
结论先行
现代95%的浏览器已经支持ECMAScript 2017语法了。我们可以通过Google提供的共建检查一下自己的网站,可以通过将编译目标调整为ES2017优化多少性能,https://estimator.dev/ 。正如Google工程师安利的:不止是提升我们自己网站的性能,节省带宽/节省运算量,同样也是降低碳排量,save the earth。
D2 语言框架专场
重构 RxJS 架构:我们如何让其更小、更快 - Ben Lesh
点击查看视频
Q: 在最开始显示代码中 bundle 的结构大小工具是什么?
A:source-map-explorer/webpack-bundle-analyzer
Q:是否能简单介绍下 rx.js 的具体功能?
A:这个是Reactive JavaScript框架,相信参考 https://rxjs.dev/guide/overview 中文 https://cn.rx.js.org/
Q:重构后代码变小变快了,但是否会降低其可读性呢?
A:可能会有这个问题,但是这些调整只会发生在局部,而不是整个产品和SDK,只要将对应的文档写好、有完备的单元测试,代码可读性还不会太受影响。
Q:架构层的重构和代码层的重构,哪个更有价值?
A:这个要具体的场景,可能要区分框架和业务产品
-
对于框架来说,架构从初始版本就确定啦,而且接口相对固定或者向前兼容,那么代码层重构是的框架更快更下,这个是最必要的。
-
对于快速开发的产品来说,如果其特性和还没有固定下来,那么架构重构可能有必要。对应成熟的产品来说,除非有更好的特性调整,才设计到架构重构,不如还是代码级别重构
揭秘TC39:ES2020和ES2021
点击查看视频
Ben 提到的 lift 函数 VS Optional Chaining
lift函数,也叫提升函数,来自函数式编程的一个重要内容: Monad。
单子(Monad)是函数式编程中的一种抽象数据类型,其特别之处在于,它是用来表示计算而不是数据的。在以函数式风格编写的程序中,单子可以用来组织包含有序操作的过程,或者用来定义任意的控制流。--维基百科
大家不要被Monad定义吓到了,Monad说简单点就是为了在函数式编程中,无副作用的解决我们代码中的错误和异常处理。函数式编程中,我们通常需要数值是不可变的。而JavaScript中的普通类型的值都是可变的。因此需要我们引入Functor函子,将JS的值包裹以达到不可变的效果。但是在我们实际操作中,可能会多层包裹了我们需要的值。因此需要Monad“探入”多层包裹,将值取出。
Monad不止取出值,也会帮我们处理掉无效值和异常。假如我们需要对异常做处理,我们需要使用Either Monad和IO Monad。这里就不展开了。讲回到lift函数,通常我们要将函数变成Monad方式,需要将函数改造一下:
const safeFindObject = R.curry((db, id) => Maybe.fromNullable(find(db,id)); //Monad是安全的,因此我们可以用safe作为前缀。
find(db,id)是不安全的,因为它的返回有可能报错或者返回无效值的,因此我们通过Maybe来包裹它。Maybe返回的结果只有2种可能:Just(value)和Nothing()。无论是哪种,都是合法的Functor可以在函数链中传递和处理。Monad是一种常见的方式,在函数式编程中,我们经常需要将不安全的函数编程安全的Monad。lift就是提升不安全的函数为Monad。
const lift = R.curry((f, value) => Maybe.fromNullable(value).map(f);
const safeFindObject = R.compose(lift, find); // 有了lift函数,我们就可以将find直接提升为Monad,而不用自己改造函数了。
在TC39的演讲中Ujjwal提到了ES2020的新特性Optional Chaining,因为有Maybe Monad的概念,其实在函数式JS编程中并不需要担心Optional的问题。
const obj = {};
let nestedProp = obj.first?.second; //ES2020 新特性写法
R.prop('second', R.prop('first', obj)); //函数式的写法R.prop类似于Maybe,有2中可能返回值value或undefined Idx → {s: a} → a | Undefined
但明显Optional Chaining的写法还是简洁了不少。
ES2020 的支持度?
比较好奇的同学可能会查一下caniuse,到底Optional Chaining的支持度是如何?
https://caniuse.com/?search=Optional%20Chaining
从截图中不难发现,目前浏览器的支持度已经85%。但如果我们看看绿色支持的浏览器部分,也就是所谓modern浏览器,都已经支持了。因此Google的浏览器大会上,特意推荐了Modern JavaScript检测,如果我们的网站的用户全是modern浏览器,其实我们已经可以在现实代码中使用ES2020了。
今年已经2021年了,JS的官方标准都已经ES2020,为什么我们还要关注ECMAScript2009?
Modern Javascript:ES2017
我们稍微保守一下,将编译目标调整为ES2017,可以优化多少性能?我们可以用Google提供的模拟工具:https://estimator.dev/ .
例如zhihu.com,如果将JS代码编译为ES2017,可以节省545kb的代码。还可以加快JS代码的速度。
JavaScript和TypeScript,都和TC39保持着良好的关系。对于JavaScript而言,ES6,也就是ECMAScript2015无疑是一次华丽的转身。从ES6开始JavaScript支持Class和块级作用域,已经一改过去难以理解的原型和作用域链模型,更加贴合主流开发语言的模式。但对于JavaScript而言距离ES6也就是ECMAScript2015已经过去5年了,目前的主流浏览器对于ECMAScript2017的支持度都已经达到了95%了。
相信目前大多数的前端同学都已经在项目中使用TypeScript作为开发语言了,只是需要修改一下配置文件,就可以对你的网站直接带来性能提升,这一点还是很有吸引力的。https://web.dev/publish-modern-javascript/#webpack
后记
JavaScript作为一门非常成功的语言,全球68%的工程师借助JavaScript实现自己的各种算法和Idea。大家可以看看Douglas Crockford 的《JavaScript: The Good Parts》,去思考一下JavaScript为何可以获得成功,为何浏览器厂商都要选择JavaScript而不是VB,applet,Flash。
JavaScript在Ecma标准组织的推进下,TC39中聚集了全球各种顶尖的人才,在推进这门语言往更加优秀的方向发展,未来更加规范,更加高效。
关注「Alibaba F2E」
回复 「PPT」一键获取大会完整PPT