网站建设 之 用js写wasm

文章探讨了WebAssembly(WASM)作为高效的低级别编程语言,如何提高Web应用的速度和安全性。尽管WASM在特定场景下提供更快的执行速度,但其工具链的复杂性和在前端项目的应用局限性使得它并未能完全替代JavaScript。V8引擎的即时编译能力能有效优化JavaScript的性能,而WASM更适合已有的C++等原生代码集成到Web环境。

为什么要这么做?编译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

<think>嗯,我现在要了解一下用RustWebAssembly(Wasm)。之前听说过Rust在系统编程方面很强大,而且Wasm可以让代码在浏览器里运行得更快。不过具体怎么开始用RustWasm呢?首先,可能需要安装一些工具吧。比如Rust本身,还有对应的Wasm工具链。 我记得Rust有个包管理器叫Cargo,可能要用它来管理项目。然后可能需要安装wasm-pack,这是不是用来编译Rust到Wasm的工具?或者还有其他的工具?比如wasm-bindgen,这个库好像用来和JavaScript交互,比如调用DOM或者处理事件什么的。 然后,具体步骤应该是创建一个新的Rust项目,配置Cargo.toml,添加依赖,比如wasm-bindgen。然后一些Rust代码,用特定的宏来暴露函数给JavaScript。接着用wasm-pack build来编译生成Wasm模块和对应的JavaScript胶水代码。之后在HTML里引入生成的JS文件,调用Rust编译出来的函数。 不过可能有些细节需要注意。比如Rust和JavaScript之间的类型转换,怎么处理字符串或者复杂的数据结构。还有性能方面,Wasm适合处理计算密集型任务,比如游戏、图像处理,而Rust的内存安全特性可能在这里特别有用。 另外,调试方面可能会有挑战,毕竟Wasm在浏览器里运行,可能需要用浏览器的开发者工具来调试。或者有没有其他工具辅助?比如console.log通过wasm-bindgen来输出日志? 还有,项目结构方面,生成的pkg目录里面有哪些文件?比如.wasm文件、.js文件、.d.ts类型定义文件,这样在TypeScript项目中也能方便使用。 可能还需要了解如何优化生成的Wasm文件大小,比如通过Rust的编译选项,或者使用wasm-opt这样的工具进行进一步优化。 有没有实际的例子?比如一个简单的加法函数,或者处理字符串返回结果。或者更复杂的,比如在Canvas上绘图,这样的例子能更好地展示Rust和Wasm的结合。 总之,步骤大概是:安装工具链,创建项目,编代码,编译,然后在Web应用中集成。过程中需要注意Rust和JavaScript的交互,以及优化和调试的方法。</think>使用 Rust 编 WebAssembly (Wasm) 的步骤如下: --- ### 1. **环境准备** - **安装 Rust 工具链** 执行命令安装 Rust(包含 Cargo): ```bash curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh ``` - **添加 Wasm 编译目标** 安装 `wasm32-unknown-unknown` 目标: ```bash rustup target add wasm32-unknown-unknown ``` - **安装 wasm-pack** 用于打包和优化 Wasm 模块: ```bash cargo install wasm-pack ``` --- ### 2. **创建 Rust 项目** - **初始化项目** ```bash cargo new --lib rust-wasm-example cd rust-wasm-example ``` - **配置 `Cargo.toml`** 添加 `wasm-bindgen` 依赖以支持 JS 交互: ```toml [lib] crate-type = ["cdylib"] [dependencies] wasm-bindgen = "0.2" ``` --- ### 3. **编 Rust 代码** 在 `src/lib.rs` 中编函数: ```rust use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn add(a: i32, b: i32) -> i32 { a + b } #[wasm_bindgen] pub fn greet(name: &str) -> String { format!("Hello, {}!", name) } ``` - **关键点** - `#[wasm_bindgen]` 宏用于导出函数到 JS。 - 支持基本类型(如 `i32`、`String`)自动转换。 --- ### 4. **编译为 Wasm** 执行命令生成 Wasm 包: ```bash wasm-pack build --target web ``` - **输出文件** 在 `pkg/` 目录下生成: - `rust_wasm_example_bg.wasm`:Wasm 二进制文件。 - `rust_wasm_example.js`:JS 胶水代码。 - TypeScript 类型定义文件(`.d.ts`)。 --- ### 5. **在 Web 中使用** 创建 `index.html`: ```html <!DOCTYPE html> <body> <script type="module"> import init, { add, greet } from './pkg/rust_wasm_example.js'; async function run() { await init(); // 初始化 Wasm 模块 console.log(add(2, 3)); // 输出 5 console.log(greet("Rust")); // 输出 "Hello, Rust!" } run(); </script> </body> ``` - **运行本地服务器** 使用工具如 `http-server` 或 `Python` 启动服务: ```bash python3 -m http.server 8000 ``` --- ### 6. **进阶场景** - **性能优化** - 启用 LTO 和优化等级: ```toml [profile.release] lto = true opt-level = 's' ``` - 使用 `wasm-opt` 进一步压缩: ```bash wasm-opt pkg/*.wasm -O3 -o pkg/optimized.wasm ``` - **复杂数据类型** 使用 `serde` 库处理 JSON: ```rust #[wasm_bindgen] pub fn process_data(json: &str) -> String { let data: serde_json::Value = serde_json::from_str(json).unwrap(); // 处理数据... } ``` --- ### 7. **调试与工具** - **控制台日志** 在 Rust 中使用 `web-sys` 输出日志: ```rust use web_sys::console; #[wasm_bindgen] pub fn log_message(msg: &str) { console::log_1(&msg.into()); } ``` - **浏览器调试** 在 Chrome DevTools 的 **Sources > Wasm** 中调试。 --- ### 8. **应用场景** - **计算密集型任务** 如物理模拟、加密算法。 - **游戏引擎** 结合 WebGL 实现高性能渲染。 - **图像处理** 用 Rust 实现滤镜算法,通过 Wasm 加速。 --- 通过以上步骤,你可以在 Rust 中编高性能的 Wasm 模块,并与 Web 生态无缝集成。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值