网站建设 之 用js写wasm

为什么要这么做?编译js比解释js更快是必然的

wasm是什么?

我期望是一个二进制文件

WebAssembly(又名wasm)是一种高效的,低级别的编程语言。 它让我们能够使用JavaScript以外的语言(例如C,C ++,Rust或其他)编写程序,然后将其编译成WebAssembly,进而生成一个加载和执行速度非常快的Web应用程序。

WebAssembly被设计为针对Size和Load Time进行优化的格式,可以在各个硬件平台上以native speed运行;

安全性:WebAssembly是运行在沙盒内的,甚至可以和当前的Java虚拟机共享一套环境,并且也遵守浏览器各种跨域不跨域的规章制度;

开放性:WebAssembly开放标准,不受任何一家厂商控制,并且被设计为可以和Java API和Context交互

短期上 WASM 显然无法替代 JS——工具链调试困难、包体积庞大冗余、调 OpenGL 都要走回 JS 到 WebGL,性能未必有保证等。我们的团队踩过移植 C++ 原生渲染引擎的坑,这东西不深度掌握的话,目前只适合保证一个原生 App 在 Web 上原汁原味地凑合能用。要想做到好用,或是封装成完整的引擎级 API 在上层用 JS 深度开发,保证让人难受。我也不知道 WASM 为什么能这么巧妙地卡在原生团队和 Web 团队各自的边界之外,在完整从下到上搞 UI 的正经前端项目上(而不是音视频等特殊场景)让两边用起来都这么费劲。

V8 几乎是这个星球上最先进的工业级脚本语言引擎。别管你代码怎么梭,只要你能让 V8 走在 Happy Path 上,那妥妥都是原生级性能。

ES 规范在不断演化。这门语言向下兼容性极佳并且仍然在进化。技术圈内独家的转译玩法,让隔壁还有人为 2 还是 3 站队的时候,前端们都在用 Chrome 明年才会支持的语法特性了。

NPM 背后那个巨大的娱乐圈,哦不,社区支持。

V8 的技术路线很可能已经到达瓶颈了——不少数据显示,这条路线的综合性能上限,大约相当于纯原生应用的 1/20,而 WASM 能优化到原生的 1/4 左右。问题在于,大多数前端应用是事件驱动的,JS 完全不会 60fps 执行,甚至初级开发者还常常随手 setTimeout 几十毫秒而不影响体验。对一个 3Ghz 的 CPU 来说,在 50ms 内它就能执行 1.5 亿条指令。这个数字除以 JS 损耗的 20 倍,那也是 750 万条指令啊。

也就是说,gcc或者别的能直接编译出wasm

js解释器是v8,js编译器是

V8 执行一段 JavaScript 代码流程


  1. 生成抽象语法树(AST)和执行上下文

无论你使用的是解释型语言还是编译型语言,在编译过程中,它们都会生成一个 AST。这和渲染引擎将 HTML 格式文件转换为计算机可以理解的 DOM 树的情况类似。

  • 第一阶段是分词(tokenize),又称为词法分析,其作用是将一行行的源码拆解成一个个 token。

  • 第二阶段是解析(parse),又称为语法分析,其作用是将上一步生成的 token 数据,根据语法规则转为 AST。

将代码翻译成字节码(Bytecode)

由于直接执行机器码效率高,但是运行在 512M 内存的手机上,内存占用问题也暴露出来了,因为 V8 需要消耗大量的内存来存放转换后的机器码。为了解决内存占用问题,V8 团队大幅重构了引擎架构,引入字节码,并且抛弃了之前的编译器,

字节码就是介于 AST 和机器码之间的一种代码。但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行。

机器码所占用的空间远远超过了字节码,所以使用字节码可以减少系统的内存使用。

执行代码即时编译器(JIT)

在 Ignition 执行字节码的过程中,如果发现有热点代码(HotSpot),比如一段代码被重复执行多次,这种就称为热点代码,那么后台的编译器 TurboFan就会把该段热点的字节码编译为高效的机器码,然后当再次执行这段被优化的代码时,只需要执行编译后的机器码就可以了,这样就大大提升了代码的执行效率。

Java 和 Python 的虚拟机也都是基于即时编译(JIT)(字节码配合解释器和编译器)实现的。具体到 V8,就是指解释器 Ignition 在解释执行字节码的同时,收集代码信息,当它发现某一部分代码变热了之后,TurboFan 编译器就把热点的字节码转换为机器码,并把转换后的机器码保存起来,以备下次使用。

因此不用js写wasm的原因是:

  1. js是嵌在html的,脱离html并没有其他应用场景,操作dom树没法用wasm

  1. v8的即时编译功能,倘若你把一个纯数学的复杂函数封装成wasm,实际上v8会智能识别热点代码并编译成机器码,倘若你把一个纯数学的复杂函数封装成wasm恰恰代表你不清楚这个知识点,实际上所有的用js转wasm都是没必要的,除非说你有很多c/c++/java/python代码,不想再转成js,想让这些代码直接被js调用,那么可以编译成wasm是有点意义的,wasm的快的意义不大

React 的开发团队可以将他们的 reconciler 代码(即 Virtual DOM)替换成 WebAssembly 版本。使用 React 的人就什么都不用做 … 他们的应用程序会像之前一样正常运行,并因 WebAssembly 收益。

WebAssembly 由于下列因素执行更快:

  • 拉取 WebAssembly 更节省时间。因为 WebAssembly 相比于 JavaScript 压缩率更高。

  • WebAssembly 解码 相比 解析 JavaScript 耗时更少。

  • 编译和优化时间更短。因为 WebAssembly 相比 JavaScript 更贴近 机器码,而且 WebAssembly 在服务端已经做过了优化。

  • 再优化 不再会发生。由于 WebAssembly 在编译时就已经内置了 类型等信息,所以 JS 引擎无需像对待 JavaScript 一样,在优化时推测类型。

  • 更短的执行时间。因为开发者不需要为了更稳定的性能,去了解使用一些 有关编译器的 奇技淫巧,而且 WebAssembly 的指令集对机器更友好。

  • 不依赖垃圾回收。因为内存是手动管理的。

实验性项目的确有人在做 从 jraphamorim/js2cballercat/walt ,基本思路都是解析js生成语法树然后接一个支持原生编译的后端。不过问题是一方面js这门语言太过灵活,而且语言本身的设计也不是为了效率,这样编译过去运行效率能提高多少很难说。另一方面真要做对性能要求很高的应用,在wasm或者在native平台上跑又面临c++、rust等语言的竞争。

所以至少目前来看,这类项目还是实验性质偏多,很难找到真正的应用价值。未来的话就看技术怎么发展,真要成熟了莫不是JS 引擎也会走一条类似 JVM -> Dalvik -> ART 的进化之路?

WASM 的确能把某些 JS 代码加速个几倍(其实大部分情况也就 1.x 倍),如果那些 JS 代码的原作者水平比较菜,那么用 cpp/rust 重写后,性能提升个十倍甚至九倍也是完全有可能的,然而由于 V8 实在太牛逼了,你费了一通老鼻子劲把一坨屎山迁到 WASM 之后,很有可能惊奇地发现它居然跑得更慢辣!

为什么呢?原因就在于 JS <-> WASM 的数据通信成本比想象中高很多,这其实是大多数需要跨语言通信的场景的瓶颈所在(比如一众小程序框架,以及 flutter 的 method channel 也有这种烦恼),尤其是当你需要把一个字符串丢进 WASM,然后再捞出来的时候,字符串拷来拷去是相当耗时的。

js 凭借强大的生态加上v8带来的优化,配合ts带来的类型检查 足以应付95%以上的业务场景。 wasm目前在前端看只要是解决了性能问题、私密代码编译加密;全局来看是提供了一个高性能统一的运行时(不区分前后端);单纯的从前端角度来看目前的确场景比较少,不过全局来看是有很多场景的,而且已经在落地使用了,比如envoy 利用wasm实现了高性能的动态扩展能力

如果你想写一个 高性能的xxx 工具用来替代市面上的 js 写的xxx 工具的话,你可能十有八九要失望了。只从 chrome 来说,因为 wasm 和 js 的字节码最后公用的 是同一个 优化编译器(turbo fan) 如果你的应用不是非常计算密集,加上js和 wasm 之间通信的额外消耗, 最后的性能可能和 js 写的应用差不多, 甚至比 js 版本还差,这个我有做过bench

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值