相关文章推荐
俊秀的海龟  ·  android ...·  7 月前    · 

WebAssembly 有一套完整的语义,实际上 wasm 是体积小且加载快的二进制格式, 其目标就是充分发挥硬件能力以达到原生执行效率

WebAssembly 运行在一个沙箱化的执行环境中,甚至可以在现有的 JavaScript 虚拟机中实现。在web环境中,WebAssembly 将会严格遵守同源策略以及浏览器安全策略。

WebAssembly 在 web 中被设计成无版本、特性可测试、向后兼容的。WebAssembly 可以被 JavaScript 调用,进入 JavaScript 上下文,也可以像 Web API 一样调用浏览器的功能。当然,WebAssembly 不仅可以运行在浏览器上,也可以运行在非web环境下。

WebAssembly支持多种语言

目前能编译成 WebAssembly 字节码的高级语言有:

AssemblyScript:语法和 TypeScript 一致,对前端来说学习成本低,为前端编写 WebAssembly 最佳选择;
c\c++:官方推荐的方式。
Rust:语法复杂、学习成本高,对前端来说可能会不适应。
Kotlin:语法和 Java、JS 相似,语言学习成本低。
Golang:语法简单学习成本低。但对 WebAssembly 的支持还处于未正式发布阶段。

开发环境搭建

安装WebAssembly for Rust 环境

安装Rust

移步到 www.rust-lang.org/tools/insta… 哦~

想要把 Rust 编译成 WebAssembly 需要一个工具: wasm-pack 。使用 wasm-pack 可以一条命令转成 WebAssembly 。 使用下面命令下载和安装:

bash cargo install wasm-pack

安装 wasm-pack 有坑

Ubuntu上可能会缺少依赖

installed libssl-dev on ubuntu 18 and still get this error:
error: failed to run custom build command for openssl-sys v0.9.39
process didn't exit successfully: /home/forecast/cs453_finalproj_backend/target/release/build/openssl-sys-864259d0b1f702fc/build-script-main (exit code: 101)
复制代码

可能需要安装:

sudo apt install pkg-config
sudo apt install libssl-dev
复制代码

来写点 Rust

新建 Rust 项目,本文以斐波那契数列为例

cargo new --lib hello-wasm-fibonacci
创建成功后提示: Created library hello-wasm-fibonacci package


项目结构:

├── Cargo .toml └── src └── lib .rs 1 directory, 2 files 复制代码

配置Cargo.toml

[package]
name = "hello-wasm"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
description = "A sample project with wasm-pack"
license = "MIT/Apache-2.0"
repository = "https://github.com/yourgithubusername/hello-wasm"
[lib]
crate-type = ["cdylib"]
[dependencies]
wasm-bindgen = "0.2"
复制代码

终于可以开始写 Rust 代码

(本文不展开 Rust 语法,专注 WebAssembly for Rust)

删除原来 lib.rs 的所有代码,在里面写想要的东西

extern crate wasm_bindgen; use wasm_bindgen::prelude::*; //生成 n 阶斐波那契数列 fn fibonacci (n: u32 ) -> u32 { if n == 0 { return 0 ; } else if n == 1 { return 1 ; } else { return fibonacci (n - 1 ) + fibonacci (n - 2 ); #[wasm_bindgen] pub fn get_fibonacci (n: u32 ) -> u32 { return fibonacci (n); 复制代码

小问号你是否有很多朋友?

  • 在 Rust 当中,库被称为 “crates”,因为我们使用的是一个外部库,所以有 "extern"
  • use xxx ::nnn::*; 是将库中的代码引入到你的代码中的使用命令。在这个情况下,将会引入 xxx::nnn 的全部模块
  • 在 #[] 中的内容叫做 "属性",并以某种方式改变下面的语句,类似于Typescript或者Java里面的注解。这里使用#[wasm_bindgen]属性,就可以把 Rust 函数开放给 JavaScript 使用。
  • 打包发布到 npm

    使用 wasm-pack 构建 WebAssembly

    wasm-pack build --scope mynpmusername

    登录 npm (默认已安装 npm )

    npm adduser
    Username: yournpmusername
    Password:
    Email: (this IS public) you@example.com
    复制代码

    进入 WebAssembly 文件目录 pkg

    cd pkg

    由于 wasm-pack 生成的 package.js 漏了_bg.js ,需要修改package.json补充

    "name" : "@mynpmusername/hello-wasm-fibonacci" , "collaborators" : [ "yourgitname <yourgitmail>" "version" : "0.1.0" , "files" : [ "hello_wasm_fibonacci_bg.wasm" , "hello_wasm_fibonacci.js" , "hello_wasm_fibonacci_bg.js" , "hello_wasm_fibonacci.d.ts" "module" : "hello_wasm_fibonacci.js" , "types" : "hello_wasm_fibonacci.d.ts" , "sideEffects" : false 复制代码

    发布到npm

    npm publish --access=public

    在前端项目中使用

    新建前端项目

    mkdir web

    新建 package.json

    "scripts" : { "serve" : "webpack-dev-server" "dependencies" : { "@mynpmusername/hello-wasm-fibonacci" : "^0.1.0" "devDependencies" : { "webpack" : "^4.25.1" , "webpack-cli" : "^3.1.2" , "webpack-dev-server" : "^3.1.10" 复制代码

    新建webpack.config.js

    const path = require('path');
    module.exports = {
      entry: "./index.js",
      output: {
        path: path.resolve(__dirname, "dist"),
        filename: "index.js",
      mode: "development"
    复制代码

    index.htm

    <!DOCTYPE html>
        <meta charset="utf-8">
        <title>hello-wasm example</title>
      </head>
        <script src="./index.js"></script>
      </body>
    </html>
    复制代码

    index.js

    const fibonacci = import("./node_modules/@yournpmusername/hello-wasm-fibonacci/hello_wasm_fibonacci.js");
    fibonacci.then(fibonacci => {
      const a = fibonacci.get_fibonacci(10)
      console.log(a)
    复制代码

    AssemblyScript

    typescript 编写 wasm

  • yarn init -y
  • yarn add @assemblyscript/loader
  • yarn add assemblyscript -D
  • npx asinit .
  • yarn asbuild or yarn asbuild:watch
  • "scripts" : { "asbuild:untouched" : "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --validate --sourceMap --debug" , "asbuild:optimized" : "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --validate --sourceMap --optimize" , "asbuild" : "npm run asbuild:untouched && npm run asbuild:optimized" , "asbuild:watch" : "onchange -i 'assembly/**/*' -- npm run asbuild" 需要用 onchange库实现开发模式 复制代码

    tsconfig.json 配置

    "extends" : "../node_modules/assemblyscript/std/assembly.json" , "include" : [ "./**/*.ts" 复制代码

    开发方式类似于 ts

    // The entry file of your WebAssembly module.
    export function add(a: i32, b: i32): i32 {
      return a + b;
    export function isPrime(x: u32): bool {
      if (x < 2) {
          return false;
      for (let i: u32 = 2; i < x; i++) {
          if (x % i === 0) {
              return false;
      return true;
    export function fabonacci(n:number):number{
      return n < 2 ? n : fabonacci(n - 1) +  fabonacci(n - 2);
    复制代码

    总结

  • 经过比较 TypeScript 生成的 wasm 速度比 Rust 快, Rust 打包出来的 wasm 比 TypeScrip 要小很多倍 (下次再详细写)
  • Rust 语言还需要学习
  • wasm 性能比 JS 要强很多, 可以应用在高性能需求场景。
  • wasm 目前打包工作流完善
  • 相关Demo

  • DEMO 1
  • DEMO 2
  • 如果懒得配环境,又想试试 WebAssembly

    可以直接用 webassembly.studio/