写点什么

冰与火之歌:JavaScript 的困境与挑战

  • 2019-12-20
  • 本文字数:4713 字

    阅读完需:约 15 分钟

冰与火之歌:JavaScript 的困境与挑战

最近几年以来,伴随着各个端平台的迅猛发展,以 TypeScript、Swift、Kotlin 和 Dart 为代表的新一代应用编程语言纷纷浮现。群雄环伺之下,JavaScript 也在不断演进。在今天正在深圳召开的GMTC2019 全球大前端技术大会上,360 高级前端架构师贺师俊发表《JavaScript 的困境与挑战》的主题演讲,分析 JavaScript 目前面对的问题以及下一步的发展趋势。


JavaScript 的时代变迁

我从 1998 年就开始写JavaScript了,那时候做的是 IE4,在座很多人可能没有用过这个东西。所以我经历了整个时代的变化。


  • 1995 年到 1999 年,是前 ES3 的时代;

  • 2000 年到 2010 年,是 ES3 的时代,我们在整个开发当中使用的都是 ES3 的版本;

  • 2008 年到 2016 年,是 Harmony 时代,今天我们基于 JavaScript 的开发,主要工具也好、方式也好,都是在 Harmony 时代积累下来的;

  • 2014 年到 2020 年,就已经进入了 ES6/Babel 的时代,Babel 在里面扮演了非常重要的角色,使我们可以在生产环境里面去使用 ES6 的特性;

  • 最后一个是我个人的预期:我认为我们下面新的时代,可能就是 TS、JS 共同构成的生态新时代。


在过去十多年里面,我经常出来讲 JavaScript 的内容,2010 年我就讲过 ES5 的话题,我当时对 JavaScript 的发展做了判断:发展方向可能有三个:API 的扩展和标准化;通用化;还有适应于 PITL(programming-in-the-large)。


2014 年我也做过演讲,当时对 ES6 做了一些总结:


  • Module 使得 JS 生态系统能重新统一;

  • Module / Class 等让 JS 更适合大型编程;

  • Promise 等将最佳实践标准化;

  • Generator / Proxy 等提供了现代语言所需的重要设施;

  • Arrow function / Destructring 等不仅是语法糖,而且填了长期以来的一些坑。


在 2015 年到 2017 年,我做过一个演讲,题目叫做《JS——世界第一程式设计语言》。在这个演讲里面,我特别提到:根据当时在推特上的统计,有 33%的人直接在生产环境使用 Babel stage0/1 presets。


传统上 JavaScript 是一个非常难以升级的语言,因为要保持线上兼容性,但是有了 Babel 之后,就变成了永远在使用最新特性。从生态上来讲,JavaScript 有浏览器,有非常多的大公司一起在这个委员会里,有世界上最大的开发者生态。

为什么会觉得 JavaScript 学不动了?

我为什么把这个拿出来说一下呢?之前的演讲,我觉得其实比较乐观,某种意义上是立了 flag。但当时 JS 已经有一些隐忧浮现了,最直接的体现是什么呢?就是所谓 js fatigue——”学不动了“。不单单包括语言,框架、工具也不断地改变,我们会觉得要学的东西很多。


当然如果大家看最近一两年会发现框架也好、工具也好,整个演进已经变慢了,已经稳定了、成熟了,如果今天我还说学不动的话,很多情况下可能会指语言本身。比如 JavaScript 一直在加新语言特性,2015 年之后,每一年都会发一个新的带年份版本的标准,每一年大概会加六到八个新的提案。包括 ES2020 也已经定了,大概会增八到九个新特性。所以这个并没有慢下来。


那为什么我们会有所谓的 JavaScript 学不动的感觉?我理解这个事情是一个边际效用下降。原本你学一个东西马上会给你带来非常大的收益,但是现在你好像每学一个新的框架,或者学一个新的语言特性,在收益上可能要打一个问号。


如果你学的东西并不能给你直接带来一个非常强的收益,包括你在生产环境里面,你觉得也不是很多地方能用到它,那么它的整个性价比可能就会下降,所以你就会发出一个好像学不动的感叹。

2020:JavaScript 的困境与挑战

所以我今天的内容,其实就是在反思,经过狂飙后,我们停下来看一看我们眼前所遇到的问题。在今年 6 月份,也就是在北京站的 GMTC 上我做过演讲,叫做《前端开发编程语言的过去、现在和未来》,讲了 TS、JS 未来面临的挑战。简单来讲就是两句话:TS 背着 JS 的包袱;JS 背着历史的包袱。


很多人认为我只要 TypeScript 就好了,但是大家要理解,TypeScript 在设计目标上要全兼容,所以如果 JavaScript 有什么问题的话,TypeScript 也跑不了。

JavaScript 的新包袱和历史包袱

JavaScript 大家知道,背着历史包袱。历史包袱不仅指老的问题,今天也改不掉,而且更重要的是,因为 JavaScript 的历史包袱导致它有一些新的设计,仍然会增加新的包袱:


第一个,JavaScript 的应用场景非常多,导致 JavaScript 的开发者社区非常复杂,有非常巨大的差异性。当我们要去对 JS 进行改进或者要加入新东西的时候,不同社区的想法、需求可能会不一样。怎么做 tradeoff?非常困难。


另外,还有像委员会语言的弊病,这个不用讳言比如 C++就是明显的委员会的语言,委员会的语言因为参与的人多,不像很多由公司主导的语言,本身的发展比较有秩序。


历史包袱我们可以展开讲一下,历史包袱简单来讲,最基本的就是,因为 JavaScript 用了这么多年,不能破坏它的兼容性,而且在所有语言里面是最没有办法改的——我们有那么多的网站跑到线上,加了任何东西都不能把原本的网站搞挂了,所以只能增加特性解决以前的问题。


比如箭头函数,它加了之后解决了很多以前 ES3 时代的函数里面的问题,也就是增加了一个所谓的 Lexical this,但是不可避免的是使 this 的语义变得更加复杂。


另外一个例子,因为我们这么多年以来,整个 JavaScript 的发展,使得我们在真正的工程当中,会存在几种不同的东西:一个叫工程方案;第二个叫事实标准;第三个才叫真的标准。这三个东西会长期共存,所以使得整个生态里面会有些复杂的问题。


对于历史包袱,我们现在的解决方法是 Polyfill 的方案。Polyfill 有广义 Polyfill 和狭义 Polyfill,到底什么叫 Polyfill?Polyfill 是已经成为了标准了,然后我们把它做出来,在没有实现的浏览器上可以用,这才叫 Polyfill。如果你是一个实验性的实现,你就不应该去修改 global 和 prototype 上的东西,因为它其实会造成很多潜在的问题。但是如果已经是一个标准了,那么去改并没有什么错。但是这个问题就是,很多开发者并不能区分这个,而且在我们的日常当中,当我们讲 Polyfill 的时候也没有刻意区分,但就会在生态中造成这样一个非常严重的问题。

Babel 带来的挑战

接下来讲 Babel,Babel 是对生态非常重要的东西。大家知道我们之前都用 presets,在 v7 的时候被取消了。主要问题是我们会无意中在 Production 中使用了 unstable features,当它发生改变,如果你在生产环节里用的话,对你本身来讲就会是非常大的挑战,对于标准本身来讲也会有很大的挑战。甚至到 stage3 都会有这样的问题。但这个事情是双刃剑,有很多东西你只有在真正的生产环境里面才能得到真的反馈,不是说光写一些 demo 就可以看出来什么问题。


第二个问题是,很多人说我今天写的不是 JavaScript,而是 BabelScript,这些特性是自己定制的语法特性。这里面有个特别的例子,是 babel-plugin-macros,这个插件非常好,原本要单独写插件,现在可以用 macros 去写,它相对是更显性的方式,明确的知道我这里用了自定义的东西。但是本质上,当你导入一个像函数的东西,它其实并不是函数。这个仍然存在一个挑战,对很多开发者来讲,是否理解是函数和不是函数的差异?


再看下 TypeScript,TypeScript 的设计原则是只有到 Stage3 才可以,TypeScript 是从 2012 年就诞生了,2012 年 ES6 还没有定案,所以 TypeScript 当年的很多特性都是 ES6 还没有定案的。如果我们看一下,这是当年 TypeScript 增加的东西,本质上 TypeScript 只是加了类型,但是在当年,因为 2012 年 ES6 还没有定案,除了类型之外,这些东西是加进去的东西。


这些东西稍微看一下,arrow function、class 没有什么问题,es module 就有问题了。它的语法不一样,这已经开始有坑了。decorator 也有问题,这是现在的提案,和 TypeScript 的提案非常不一样,所以 TypeScript 需要一个编译开关才能使用,这也是 decorator 不太好的状态。包括最后这两个,private property 和 public property 语法语义和现在的 stage3 的 class fields 完全不一样,对 TypeScript 来说非常痛苦。


然后我们再来看一个例子,叫做 ESLint。它采用的方针更加保守了,它只是在 Stage4 的时候才会做跟这些新特性有关的新规则。这种方式也避免了前面很多问题。


ESLint 会导致两个问题:第一个我们很多人已经在做更早的 Stage3 的东西,但 Stage3 的东西也需要保护,而且更需要保护;第二个问题就是,在制订标准的时候,缺乏 lint 社区的反馈。


有一个有趣的事情是,在整个 ES6 的发展当中,很多的提案是遵循一个叫做 Maximally Minimal 的设计哲学,最大化的最小化,我们只加那些最最重要的东西,如果翻译过来的话叫先解决温饱再考虑小康,所以 ES6 很多东西确实解决痛点,但很多时候 ES6 的东西并不能完全满足你的所有需要。


比如 ES6 加了 Map 和 Set,但这两 API 只能满足你最基本的需求。所以这也是一个双刃剑,好的地方是,我们只有通过这样的设计,才能在当时那么快的把 ES6 做出来,否则可能永远都做不出来。到底怎么样才是真正满足所有人需求?这个事情定义不清楚。


今天来讲,我们会发现,很多时候我们温饱都已经解决了,现在大家讨论的都是小康问题。怎么让特性用得更好更爽。但这个问题就是前面讲的,因为开发者社区非常复杂,每个人的需求都不一样,最大的问题是谁能代表开发者?这其实一个非常难以回答的问题。


举个例子——Map.prototype.upsert(),看名字猜得出来吗?估计猜不太出来。我个人认为只有非常有经验的开发者,才可能比较需要这个东西。一般的开发者其实是不是真的需要,要打个问号。同时对新手来讲,理解的成本也比较高。所以这里有个问题,我们怎么衡量成本和收益?其实是非常困难的。


最后,我讲一下有争议的事,比如说我们现在对 Top-level Await、Class fields 这两个提案都不太满意,当然我们技术上可以有很多的讨论,但实际上这个事情一句话讲就是改革进入深水区,就是好做的都做完了,剩下的都是难搞的。这两个其实都是 ES6 时代遗留至今的问题。


最后再举一个例子——Pipeline Operator。现在 Pipeline 有两种不同的竞争提案,第一种叫 F# Style,另外一种方式叫 Smart style。所以这其实是两难选择,我们是希望更符合 FP 的主流还是更普适现有整个 JavaScript 的生态,这是非常难做的选择。


还有 Binary AST,也是一个提案,它相当于字节码,它有个很大的好处就是整个加载速度会非常快的提升。所以这样一个提案肯定是我们所有人都很喜欢的,特别是做 Web 的人会非常喜欢。但是这个现在也处于一个比较难推进的状态,为什么呢?讲一个很简单的原因就是,当你有了 Binary AST 之后,所有语言特性都得考虑,在这里面怎么把它加进去,字节码里面怎么把它加进去,所以困难程度直接翻番了。


大家看到很多问题都是有两面性,这是改革进入深水区遇到的很多问题。包括不同平台的需求,比如 Web 和 Node 的平台,这两个平台的需求不一样。


还有性能和动态性的矛盾,我们做一个东西既希望性能好,又希望符合 JavaScript 的传统,这里面最简单的例子就是 decorator。所以会遇到非常多的矛盾问题。

JavaScript 的转折点:未来何去何从?

讲了这么多,可能最重要的问题就是:到底我们整个发展有没有 Roadmap?答案是没有。这就是委员会里面的一个问题,进一步来讲,它也没有明确的主导者,如果没有 Roadmap,全局上怎么解决这个事情就不好说了。


所以我们今天进展到这样一个地步——JavaScript 是非常成功的语言,但到现在是一个转折点,我们要停下来看一看:它再往下怎么样发展才会更好?


嘉宾介绍:


贺师俊(网名 Hax),360 高级前端架构师,十多年来一直活跃在前端和 JavaScript 社区。对多项 Web 标准有微小贡献,对 Groovy 语言并间接对 Swift 语言有微小贡献,近年来参与了诸多 ECMAScript 新草案的讨论。2019 年 7 月起成为 360 的 TC39 代表。


2019-12-20 18:087036

评论 1 条评论

发布
用户头像
三大框架趋于稳定
2020-01-15 10:15
回复
没有更多了
发现更多内容

数据库每日一题---第18天:每天的领导和合伙人

知心宝贝

数据库 大数据 前端 后端 6月月更

Any to Any 实时变声的实现与落地丨RTC Dev Meetup

声网

音频 RTC Dev Meetup 生态专栏 语音处理

喜讯!云效度量能力获信通院先进级评估

阿里云云效

云计算 阿里云 DevOps 研发效能 研发

小红书严打买卖账号及刷量作弊行为:必须维护平台的公信力

石头IT视角

接口测试(apipost、jmeter和python脚本)——测试工具

Xd

Java 后端 接口测试

Java Core 「13」ReentrantReadWriteLock 再探析

Samson

学习笔记 Java core 6月月更

uni-app进阶之创建组件/原生渲染【day9】

恒山其若陋兮

6月月更

在线文本列表批量添加行号工具

入门小站

工具

服务治理的工作内容

阿泽🧸

微服务 6月月更

稳住了,别抖!—— 看GetX 的Worker如何防抖

岛上码农

flutter ios 前端 安卓开发 6月月更

JVM调优简要思想及简单案例-新生代回收算法

zarmnosaj

6月月更

在线JSON转YAML工具

入门小站

工具

携手腾竞体育后,英特尔IMC如何加速电竞生态正循环?

科技之家

「微服务的细节」—— 周期性注册 or 一次性注册

袁世超

微服务

Larix真正的去中心化借贷平台,并开启double Mining活动

鳄鱼视界

数据资产管理

奔向架构师

数据资产 数据管理 6月月更

新课上线 | 每次 5 分钟,轻松玩转阿里云容器服务!

阿里巴巴云原生

阿里云 云原生 容器服务

Discourse 新用户可插入媒体的数量

HoneyMoose

flutter系列之:flutter中的builder

程序那些事

flutter 程序那些事 6月月更

Android 修改系统音量及监听

yechaoa

android 6月月更 AudioManager

一问带你彻底了解JVM-Java虚拟机内存区域详解

派大星

JVM

攻防演练中红队的内网横向扩展

穿过生命散发芬芳

6月月更 攻防演练

浅谈融云即时通讯服务「日志优化」

融云 RongCloud

统一日志

卢卡多多

日志 6月月更

AWS的运营管理类服务

冯亮

云计算 AWS

vue导航路由

小恺

6月月更

leetcode 221. Maximal Square 最大正方形(中等)

okokabcd

LeetCode 动态规划 数据结构与算法

军体拳代码

工程师日月

6月月更

透过华为军团看科技之变(四):互动媒体(音乐)

脑极体

linux之我常用的20条命令( 之三)

入门小站

Linux

百度安全再次亮相高性能计算国际顶会SC 2022 — 采用Fuzzing技术防护高性能计算静默数据损坏安全风险

百度安全

百度安全 百度安全实验室 高性能计算国际顶会 SC 2022 Fuzzing技术防护

冰与火之歌:JavaScript 的困境与挑战_大前端_贺师俊_InfoQ精选文章