WebAssembly 初体验

简介: WebAssembly 初体验

640.jpg


好了,我又想起公众号密码了 - -


2017年,WebAssembly(wasm)推出了第一个版本。2019年12月5日,wasm被W3C推荐,与HTML,CSS,JavaScript一起,成为了Web开发的第四种语言。

wasm已经不算是新技术了。由于今年的工作中会涉及到wasm,故需要进行较为系统的学习。本公众号也会不定期更新相关文章。


WebAssembly 是什么


WebAssembly是一种新的编码方式,具有二进制格式,是一种低级的类汇编语言,可以在现代的浏览器中运行。wasm在设计之初,就是为了提供比js更快速的编译和执行。开发者可以使用自己熟悉的语言(比如c/c++,golang等)编写代码,最终编译为wasm,在浏览器中运行。wasm被限制运行在一个安全的沙箱执行环境中。像其他网络代码一样,它遵循浏览器的同源策略和授权策略。wasm的出现,使得之前只运行JavaScript的虚拟机现在可以加载和运行两种类型的代码——JavaScript和WebAssembly。当前,四大浏览器(FireFox,Chrome,Edge,Safari)均已支持了wasm。

wasm有以下几个关键的概念(摘抄自MDN):


  • 模块:表示一个已经被浏览器编译为可执行机器码的WebAssembly二进制代码。一个模块是无状态的,并且像一个二进制大对象(Blob)一样能够被缓存到IndexedDB中或者在windows和workers之间进行共享(通过postMessage() 函数)。一个模块能够像一个ES2015的模块一样声明导入和导出。
  • 内存:ArrayBuffer,大小可变。本质上是连续的字节数组,WebAssembly的低级内存存取指令可以对它进行读写操作。
  • 表格:带类型数组,大小可变。表格中的项存储了不能作为原始字节存储在内存里的对象的引用(为了安全和可移植性的原因)。
  • 实例:一个模块及其在运行时使用的所有状态,包括内存、表格和一系列导入值。一个实例就像一个已经被加载到一个拥有一组特定导入的特定的全局变量的ES2015模块。


wasm有两种格式,一种二进制代码格式,文件后缀为.wasm,一种文本格式,后缀名为:.wat。


Wasm代码实例


说了这么多,下面直接来看一个实例。由于之前写过一段时间go,对go稍微熟悉点,所以这里以go为例。

简单的一段代码:


package mainimport (  "fmt")func add(a int, b int) int {  return a + b;}func main() {  c := add(1, 2);  fmt.Println(c);}


通过go的命令行工具,


GOARCH=wasm GOOS=js go build -o test.wasm


将其转为了.wasm文件后,长这个样子:

640.png


以上是wasm的二进制格式表示。


如何在浏览器中使用wasm


浏览器提供了一个 WebAssembly 对象来聚合所有wasm相关的功能。


640.png


我们怎么运行上面例子中的wasm代码呢?通过上述编译方法,go在编译成wasm后,想要在浏览器中运行,需要一段"jsbridge"代码,也就是胶水代码。通过下面的命令,导出go的胶水代码


cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" wasm_exec.js

然后在页面中引用就可以了。


<html>    <!-- 引用胶水代码 -->    <script src="wasm_exec.js"></script>    <script>        const go = new Go();        fetch('test.wasm')            .then(rsp => {                // wasm二进制代码转换成arrayBuffer                return rsp.arrayBuffer();            })            .then(bytes => {                 // 实例化wasm模块                return WebAssembly.instantiate(bytes, go.importObject)            }).then(result => {                // 拿到模块实例,直接执行                const instance = result.instance;                go.run(instance)            });</script></html>

在浏览器的控制台中,我们就可以看到go代码的执行结果了:

640.png

那么,如果想要在浏览器内,通过js调用go代码中的方法怎么办呢?

首先需要先修改go代码:


package mainimport (  "fmt"  "syscall/js" // 引入必要的依赖)
func add(a int, b int) int {  return a + b;}
// 将add函数包装一层func jsAdd(this js.Value, args []js.Value) interface{} {  return js.ValueOf(add(args[0].Int(),args[1].Int()))}
func main() {  c := add(1, 2);  fmt.Println(c);  // 在 main 函数中,创建了信道(chan) done,阻塞主协程(goroutine)。jsAdd 如果在 JavaScript 中被调用,会开启一个新的子协程执行。  done := make(chan int, 0)  // 将 jsAdd 函数注册到浏览器环境中  js.Global().Set("jsAdd", js.FuncOf(jsAdd))  <-done}

重新编译成wasm后,在页面中看下效果:

640.png


wasm的性能如何


wasm不仅有二进制代码格式,也有文本格式(后缀为:wat)。文本格式主要是为了方便人类阅读和编辑。我上网找了一个计算斐波拉契数列的wat文本格式代码,通过斐波拉契数列来看一下wasm的性能。wat代码如下:


(module (export "fib" (func $fib)) (func $fib (param $n i32) (result i32)  (if   (i32.lt_s    (get_local $n)    (i32.const 2)   )   (return    (i32.const 1)   )  )  (return   (i32.add    (call $fib     (i32.sub      (get_local $n)      (i32.const 2)     )    )    (call $fib     (i32.sub      (get_local $n)      (i32.const 1)     )    )   )  ) ))

将其编译成wasm后,放入浏览器中运行。


640.png


我们来看一下斐波拉契数列计算到40时,两者的耗时:


640.png


可以看到,wasm版本的耗时比js版本的耗时少了 20% 多。wasm确实有性能优势。


稍微总结一下


经过一些阅读与实践,大概了解了wasm是什么以及最简单的使用方法。本文没有深入到wasm的一些细节点,不过不难体会到,wasm在性能上确实会有优势,并且wasm可以作为其他高级语言与js的"桥梁"。图片、视频等处理算法,可以比较方便移植到浏览器上直接运行了。


更多关于wasm的内容,后面再探索总结吧。

相关文章
|
存储 Rust 前端开发
给 Web 前端工程师看的用 Rust 开发 wasm 组件实战
wasm 全称 WebAssembly,是通过虚拟机的方式,可以在服务端、客户端如浏览器等环境执行的二进制程序。它有速度快、效率高、可移植的特点
201 0
|
4月前
|
Rust 前端开发 JavaScript
Tauri框架:使用Rust构建轻量级桌面应用
Tauri是一个用Rust构建的开源框架,用于创建轻量、安全且高效的跨平台桌面应用,结合Rust与Web技术(HTML/CSS/JS)。它遵循最小权限原则,仅在必要时调用OS API。Tauri架构包括Rust后端、Web前端、Tauri API和包装器。通过`cargo tauri init`可创建新项目,Rust后端处理系统交互,前端负责UI,两者通过Tauri API通信。Tauri支持自定义API、集成前端框架、资源管理、自动更新、系统集成和安全配置。此外,Tauri拥有插件系统和丰富的扩展能力,提供调试和测试工具,并有性能优化建议。
278 4
|
5月前
|
缓存 Rust 前端开发
【一起学Rust | 框架篇 | Tauri2.0框架】Tauri2.0环境搭建与项目创建
【一起学Rust | 框架篇 | Tauri2.0框架】Tauri2.0环境搭建与项目创建
551 0
|
5月前
|
前端开发 JavaScript 开发工具
新一代前端开发工具:探索WebAssembly在前端领域的应用
本文将介绍WebAssembly在前端开发领域的应用,探讨其在提升前端性能、扩展开发语言选择、优化代码大小等方面的优势。通过深入分析WebAssembly的特性和优势,以及实际案例展示,帮助读者更好地理解和应用这一新一代前端开发工具。
|
Rust JavaScript 前端开发
WebAssembly 入门
本文讲解了 WebAssembly 的入门知识,包括理论以及一些实践过程
12748 8
|
JavaScript C# C++
如何使用单纯的`WebAssembly`
如何使用单纯的`WebAssembly`
108 0
如何使用单纯的`WebAssembly`
|
存储 缓存 移动开发
构建跨平台应用的利器——UniApp入门指南
构建跨平台应用的利器——UniApp入门指南
|
缓存 JavaScript 前端开发
从0到1构建跨平台Electron应用,这篇文章就够了
Electron是一个可以直接开发构建跨平台应用的库,简单、快捷。 《Electron从0到1构建跨平台应用》这篇文章,我摘录了我自己在真实项目中,从开发到生成安装包的要点。
824 0
|
开发框架 JavaScript 前端开发