谁将取代 JavaScript?
谁能取代 JavaScript 似乎是一个老生常谈的话题,很多人都提出过各自不同的看法。本文作者则提出了一个新的视角供你参考:JavaScript 风头正劲,但 WebAssembly 可能已经敲响了它的丧钟。
有些编程语言很受欢迎,还有些语言只是一种"必需品"而已。对于许多程序员来说,JavaScript 就属于后者——每一位前端开发人员都需要理解这门语言,但人们用不着真心喜爱它。
十年前,我们还很难看出 JavaScript 将会统治世界。Java、Flash 和 Silverlight 等平台曾位于舞台中心。这三大技术都需要使用浏览器插件来完成工作,它们也都用另一种用户界面方法取代了 HTML。这种方法使它们在功能层面遥遥领先于 JavaScript——比如,早在video元素、CSS 动画规范或 HTML 画布诞生之前,我们就可以添加视频、动画和绘图。但这种方法也让它们走入了黄昏。当移动浏览需求爆炸式增长,HTML 开始拥抱这一趋势的时候,其他平台就成为了时代的眼泪。
这段讽刺的历史如今要重演了。在 JavaScript 征服世界的同时,有人播下了一颗小小的种子,这颗种子可能在将来的某一天成长为参天大树,敲响 JavaScript 的丧钟——这就是名为 asm.js 的实验性技术。
不过展开这个故事之前,我们先退后一步看一看现状。
转译:当前方法
自从我们有了 JavaScript,开发人员就一直在设法绕开它。早期的一种方法是使用插件把代码从浏览器中剥离(结果失败了)。另一个想法是开发出可以转换代码的开发工具,换句话说就是采用另一种更受人尊敬的语言编写代码,然后将其转换为 JavaScript。这样开发人员就可以获得他们需要的全平台支持,同时并不会弄脏自己的双手。
将一种语言转换为另一种语言的过程称为 转译(transpiling),其存在一些明显的缺陷。高级语言有着各自不同的功能、语法和习惯表达,你不可能把一种语言中的每一行都映射到另一种语言中的等效构造上。就算你能做到这一点也会留下许多坑。如果社区停止开发你最喜欢的转译器该怎么办?如果转译器自己就引入了许多错误该怎么办?想要插入 Angular、React 或 Vue 这样的 JavaScript 框架又要怎么解决?如果你会的语言和同事不一样,你又该如何与团队协作?
编程行业中很多情况本质都是一样的,那就是一种工具的水平主要取决于它背后社区的繁荣程度。
如今转译器是很常见的,但它们的用途几乎只有一条——那就是处理向后兼容性。
开发人员可能会编写最前沿的 JavaScript,然后使用 Babel 这样的转译器将其代码转换为等效(但不太优雅)的老式 JavaScript 代码,以便在所有位置运行。或者更好的办法是,他们使用 TypeScript(一种现代化的 JavaScript,添加了强类型、泛型和非空类型等功能),然后将其转换为 JavaScript。但不管是哪种方法,你都
逃不出 JavaScript 的手掌心。
Asm.js:垫脚石
全新可能性的第一缕曙光来自 asm.js,这是 Mozilla 的开发人员在 2013 年完成的一项古怪的实验。当时他们正在寻找在浏览器中运行高性能代码的方法。但 asm.js 并没有像插件那样尝试在浏览器外部运行;相反,它的目标是直接通过 JavaScript 虚拟机打出一条通道。
从本质上讲,asm.js 是简洁且优化的 JavaScript 语法。它比普通的 JavaScript 运行得更快,因为它避免了这种语言中较慢的动态部分。而且支持它的 Web 浏览器也可以应用其他优化,从而显著提升性能。换句话说,asm.js 遵循黄金法则——不要破坏 Web——同时提供了一条未来改进的途径。Firefox 团队使用 asm.js 以及称为 Emscripten 的转译工具把用 C++ 构建的实时 3D 游戏放入 Web 浏览器中,需要的条件仅仅是 JavaScript 和达成目标的雄心壮志。
运行在 asm.js 上的虚幻引擎
asm.js 的最大意义在于,它迫使开发人员重新思考 JavaScript 扮演的角色。Asm.js 代码是 JavaScript,但这些代码并不是让程序员手工读写的。相反,asm.js 代码是由自动化流程(转译器)构建,并直接提供给浏览器的。JavaScript 是媒介,但不是信息本身。
WebAssembly:一项新技术
尽管 asm.js 实验做出了一些令人眼花缭乱的演示,但主流开发人员大都无动于衷。对他们来说,这只是又一项有趣的技术概念而已。但随着 WebAssembly 的诞生,情况发生了变化。
WebAssembly 既是 asm.js 的后继产品,又是一项截然不同的技术。这是一种紧凑的二进制代码格式。像 asm.js 一样,WebAssembly 代码也被输入到 JavaScript 执行环境中。它具有相同的沙箱和相同的运行时环境。与 asm.js 一样,WebAssembly 的转译机制也可以进一步提升效率。但是现在这种潜力比以前大得多,并且浏览器可以完全跳过 JavaScript 解析阶段。对于一段普通的逻辑(例如一段很费时的计算)来说,WebAssembly 的执行速度远远快于常规的 JavaScript,几乎与原生编译的代码一样快。
WebAssembly 处理流水线的简化视图
想知道 WASM 长什么样的话,可以想象你有一个 C 函数,如下所示:
int factorial(int n) {
if (n == 0)
return 1;
else
return n * factorial(n-1);
}
它编译成 WASM 代码后就成了下面这个样子:
get_local 0
i64.eqz
if (result i64)
i64.const 1
else
get_local 0
get_local 0
i64.const 1
i64.sub
call 0
i64.mul
end
开始向网络中传送时,WASM 代码会进一步压缩为二进制编码。
WebAssembly 设计为编译器的目标。你永远用不着亲自动手写它的代码。(但如果你想深入探索一番,自己写也是可以的。)
WebAssembly 诞生于 2015 年。今天,桌面和移动设备上的四大浏览器(Chrome、Edge、Safari 和 Firefox)都完全支持它。Internet Explorer 是不支持的,尽管可以将 WebAssembly 代码转换为 asm.js 来实现向后兼容。(兼容性的代价是性能损失。请让 IE 走进历史吧!
WebAssembly 与 Web 开发的未来
WebAssembly 是开箱即用的,为开发人员提供了一种(通常使用 C++)编写优化代码逻辑的途径。这是强大的能力,但应用范围相对较窄。当你需要改善复杂计算的性能时这种方法很有用(例如,fastq.bio 使用 WebAssembly 加快了他们的 DNA 测序计算。。如果你要移植高性能游戏或编写在浏览器中运行的模拟器,这种能力也很重要。但如果这就是 WebAssembly 的全部实力,那其实也没什么可激动的——光是这点东西可没希望取代 JavaScript。但是 WebAssembly 还为框架开发人员提供了一条狭窄的路径,使他们可以将其平台塞入 JavaScript 环境中。
这下事情就变得有趣了。WebAssembly 无法绕开 JavaScript,因为它已锁定在 JavaScript 运行时环境中了。实际上,WebAssembly 需要与最起码 少量 的普通 JavaScript 代码搭配运行,因为前者无法直接访问网页。这意味着如果不经过 JavaScript 层,WASM 就无法操纵 DOM 或接收事件。
听起来这个限制是致命的。但是聪明的开发人员已经找到了通过 WebAssembly 塞进他们自己的运行时的办法。例如,微软的 Blazor 框架会下载一个小型 .NET 运行时作为已编译的 WASM 文件。这个运行时处理 JavaScript 互操作,并提供基本服务(如垃圾回收)和更高级别的功能(布局、路由和用户界面小部件等)。换句话说,Blazor 使用了一个驻留在另一个虚拟机中的虚拟机,堪称《盗梦空间》级别的悖论,也是一种在浏览器中运行非 JavaScript 应用程序框架的巧妙方法。
Blazor 并不是唯一一个由 WebAssembly 支持的实验。还可以看看 Pyodide,其旨在将 Python 放入浏览器中,它带有用于数据分析的高级数学工具包。
这就是未来。WebAssembly 最初是为了满足 C++ 和 Rust 等需求而诞生的,却很快就被用来开发目标更加远大的实验。不久的将来,它就会支持非 JavaScript 框架与 Angular、React 和 Vue 等基于 JavaScript 的对手同台竞技。
而且 WebAssembly 仍在迅速发展。它目前的实现只是一款最小可行产品——只够在一些重点场景中使用,还不是万能的 Web 开发方法。随着 WebAssembly 的推广,它也会不断进化。如果像 Blazor 这样的平台流行起来,WebAssembly 可能会增加对直接 DOM 访问的支持。浏览器开发商还在计划添加垃圾回收和多线程支持,这样运行时就不需要自己实现这些细节。
看起来这条发展道路漫长而充满变数,但请回想一下 JavaScript 的历史。首先,我们发现 JavaScript 能做到的事情都会写成 JS 代码。然后我们意识到,如果一件事情重复的次数够多,浏览器就会让它做得更好,如此循环。如果 WebAssembly 开始流行,它将进入一个良性循环,不断发展,很容易就能超越 JavaScript 的固有优势。
人们经常说,WebAssembly 并不是用来代替 JavaScript 的。但这句话对所有革命性平台都是一样的。JavaScript 当初并不是要取代嵌入浏览器的 Java。Web 应用程序并非旨在替代桌面应用。但一旦能做到这些,它们必然会走上那条路。
作者介绍:
Matthew MacDonald 是教师、程序员和许多大部头的作者。
作者:Matthew MacDonald
译者:王强
来源:InfoQ