俄罗斯贵宾会-俄罗斯贵宾会官网
做最好的网站

WebAssembly 对比 JavaScript 及其使用场景

WebAssembly 对比 JavaScript 及其使用场景

2018/05/17 · JavaScript · 滚动

原文出处: Alexander Zlatkov   译文出处:Troland   

编写加载函数(loader)

function loadWebAssembly (path) {

  return fetch(path)                   // 加载文件        

    .then(res => res.arrayBuffer())    // 转成 ArrayBuffer

    .then(WebAssembly.instantiate)     // 编译 + 实例化

    .then(mod => mod.instance)         // 提取生成都模块

}

完成了上边的操作,就可以直接使用 loadWebAssembly 这个方法加载 wasm 文件了,它相当于是一个 wasm-loader ;返回值是一个 Promise.

loadWebAssembly('path/to/math.wasm')

  .then(instance => {

    const { add, square } = instance.exports

    // ...

})

更完善的loader

function loadWebAssembly(filename, imports = {}) {

return fetch(filename)

    .then(response => response.arrayBuffer())

    .then(buffer => WebAssembly.compile(buffer)) 

    //WebAssembly.compile 可以用来编译 wasm 的二进制源码,

    //它接受 BufferSource 格式的参数,返回一个 Promise。

    .then(module => {           

        imports.env = imports.env || {};

        // 开辟内存空间 && 创建变量映射表

        Object.assign(imports.env, {

            memoryBase: 0,

            tableBase: 0,

            memory: new WebAssembly.Memory({ initial: 256, maximum: 256 }),

            table: new WebAssembly.Table({ initial: 0, maximum: 0, 

                    element: 'anyfunc' })

        })

        // 创建 WebAssembly 实例

        return new WebAssembly.instantiate(module, imports)

    })

}

ArrayBuffer 做了两件事情,一件是做 WebAssembly 的内存,另外一件是做 JavaScript 的对象。

俄罗斯贵宾会,它使 JS 和 WebAssembly 之间传递内容更方便。 使内存管理更安全。

这个 loadWebAssembly 函数还接受第二个参数,表示要传递给 wasm 的变量,在初始化 WebAssembly 实例的时候,可以把一些接口传递给 wasm 代码。

番外篇

打开 webassembly 官网就可以在头部醒目地看到显示它兼容的浏览器。分别是火孤,Chrome,Safari,IE Edge。点开 learn more 可以查看到这是于 2017/2/28 达成一致推出浏览器预览版。现在各项工作开始进入实施阶段了,相信在未来的某个时刻就可以在生产环境使用它了。官网上面介绍了一个 JavaScript 的子集 asm.js。另外,这里有一个 WebAssembly 和 JavaScript 进行性能比对的测试网站

1 赞 收藏 评论

俄罗斯贵宾会 1

Rust编译为webAssembly

1.安装Rustup

Rustup是一个命令行应用,能够下载并在不同版本的Rust工具链中进行切换

brew install cargo

curl https://sh.rustup.rs -sSf | sh

source $HOME/.cargo/env 

source  ~/.bash_profile

rustup target add wasm32-unknown-unknown --toolchain nightly 

cargo install --git https://github.com/alexcrichton/wasm-gc 

//减小wasm的size

cargo可以将整个工程编译为wasm,首先使用cargo创建工程:

cargo new project

下一步,把下面的代码加到 Cargo.toml 中

[lib]

path = "src/lib.rs"

crate-type = ["cdylib"]

2.demo:https://github.com/jakedeichert/wasm-astar

编译:

cargo +nightly build --target wasm32-unknown-unknown --release

俄罗斯贵宾会 2

编译出来的wasm大小为82Kb,使用wasm-gc压缩 small-wasm_astar.wasm 的大小为 67Kb

wasm-gc wasm_astar.wasm small-wasm_astar.wasm

俄罗斯贵宾会 3

WebAssembly 使用场景

WebAssembly 的最初版本主要是为了解决大量计算密集型的计算的(比如处理数学问题)。最为主流的使用场景即游戏-处理大量的像素。

你可以使用你熟悉的 OpenGL 绑定来编写 C++/Rust 程序,然后编译成 wasm。之后,它就可以在浏览器中运行。

浏览下(在火孤中运行)-http://s3.amazonaws.com/mozilla-games/tmp/2017-02-21-SunTemple/SunTemple.html。这是运行于Unreal engine(这是一个可以用来开发虚拟现实的开发套件)中的。

另一个合理使用 WebAssembly (高性能)的情况即实现一些处理计算密集型的库。比如,一些图形操作。

正如之前所提到的,wasm 可以有效减少移动设备的电力损耗(依赖于引擎),这是由于大多数的步骤已经在编译阶段提前处理完成。

未来,你可以直接使用 WASM 二进制库即使你没有编写编译成它的代码。你可以在 NPM 上面找到一些开始使用这项技术的项目。

针对操作 DOM 和频繁使用平台接口的情况 ,使用 JavaScript 会更加合理,因为它不会产生额外的性能开销且它原生支持各种接口。

在 SessionStack 我们一直致力于持续提升 JavaScript 的性能以编写高质量和高效的代码。我们的解决方案必须拥有闪电般的性能因为我们不能够影响用户程序的性能。一旦你把 SessionStack 整合进你的网络应用或网站的生产环境,它会开始记录所有的一切:所有的 DOM 变化,用户交互,JavaScript 异常,堆栈追踪,失败的网络请求和调试数据。所有的这一切都是在你的生产环境中产生且没有影响到你的产品的任何交互和性能。我们必须极大地优化我们的代码并且尽可能地让它异步执行。

我们不仅仅有库,还有其它功能!当你在 SessionStack 中重放用户会话,我们必须渲染问题产生时你的用户的浏览器所发生的一切,而且我们必须重构整个状态,允许你在会话时间线上来回跳转。为了使之成为可能,我们大量地使用异步操作,因为 JavaScript 中没有比这更好的替代选择了。

有了 WebAssembly,我们就可以把大量的数据计算和渲染的工作移交给更加合适的语言来进行处理而把数据收集和 DOM 操作交给 JavaScript 进行处理。

webAssembly.Memory

当 WebAssembly 模块被实例化时,它需要一个 memory 对象。你可以创建一个新的WebAssembly.Memory并传递该对象。如果没有创建 memory 对象,在模块实例化的时候将会自动创建,并且传递给实例。

var myMemory = new WebAssembly.Memory(memoryDescriptor);

memoryDescriptor (object)

initial maximum 可选

内存模型

俄罗斯贵宾会 4

WebAssembly 可信和不可信状态

举个栗子,一个 C++ 的程序的内存被编译为 WebAssembly,它是整段连续的没有空洞的内存块。wasam 中有一个可以用来提升代码安全性的功能即执行堆栈和线性内存隔离的概念。在 C++ 程序中,你有一块动态内存区,你从其底部分配获得内存堆栈,然后从其顶部获得内存来增加内存堆栈的大小。你可以获得一个指针然后在堆栈内存中遍历以操作你不应该接触到的变量。

这是大多数可疑软件可以利用的漏洞。

WebAssembly 采用了完全不同的内存模型。执行堆栈和 WebAssembly 程序本身是隔离开来的,所以你无法从里面进行修改和改变诸如变量值的情形。同样地,函数使用整数偏移而不是指针。函数指向一个间接函数表。之后,这些直接的计算出的数字进入模块中的函数。它就是这样运行的,这样你就可以同时引入多个 wasm 模块,偏移所有索引且每个模块都运行良好。

更多关于 JavaScript 内存模型和管理的文章详见这里

webAssembly的方法

源码映射

当你压缩了 JavaScript 代码的时候,你需要有合适的方法来进行调试。

这时候源码映射就派上用场了。

大体上,源码映射就是把合并/压缩了的文件映射到未构建状态的一种方式。当你为生产环境进行代码构建的时候,与压缩和合并 JavaScript 一起,你会生成源码映射用来保存原始文件信息。当你想在生成的 JavaScript 代码中查询特定的行和列的代码的时候,你可以在源码映射中进行查找以返回代码的原始位置。

由于没有规范定义源码映射,所以目前 WebAssembly 并不支持,但最终会有的(可能快了)。

当你在 C++ 代码中设置了断点,你将会看到 C++ 代码而不是 WebAssembly。至少,这是 WebAssembly 源码映射的目标吧。

asm.js

asm.js 是 javascript 的子集,是一种语法。用了很多底层语法来标注数据类型,目的是提高 javascript 的运行效率,本身就是作为 C/C++ 编译的目标设计的(不是给人写的)。 WebAssembly 借鉴了这个思路,做的更彻底一些,直接跳过 javascript ,设计了一套新的平台指令。

目前只有 asm.js 才能转成 wasm,普通 javascript 是不行的。虽然 Emscripten 能生成 asm.js 和 wasm ,但是却不能把 asm.js 转成 wasm 。想要把 asm.js 编译成 WebAssembly,就要用到他们官方提供的 Binaryen 和 WABT (WebAssembly Binary Toolkit) 工具。

           Binaryen                WABT

math.js   -------->   math.wast   ------->   math.wasm

内存垃圾回收

你已经知晓 JavaScript 的内存管理是由内存垃圾回收器处理的。

WebAssembly 的情况有点不太一样。它支持手动操作内存的语言。你也可以在你的 wasm 模块中内置内存垃圾回收器,但这是一项复杂的任务。

目前,WebAssembly 是专门围绕 C++ 和 RUST 的使用场景设计的。由于 wasm 是非常底层的语言,这意味着只比汇编语言高一级的编程语言会容易被编译成 WebAssembly。C 语言可以使用 malloc,C++ 可以使用智能指针,Rust 使用完全不同的模式(一个完全不同的话题)。这些语言没有使用内存垃圾回收器,所以他们不需要所有复杂运行时的东西来追踪内存。WebAssembly 自然就很适合于这些语言。

另外,这些语言并不能够 100% 地应用于复杂的 JavaScript 使用场景比如监听 DOM 变化 。用 C++ 来写整个的 HTML 程序是毫无意义的因为 C++ 并不是为此而设计的。大多数情况下,工程师用使用 C++ 或 Rust 来编写 WebGL 或者高度优化的库(比如大量的数学运算)。

然而,将来 WebAssembly 将会支持不带内存垃圾回功能的的语言。

系统">开发前准备工作(MAC系统)

1.安装 cmake brew install cmake

2.安装 pyhton brew insatll python

3.安装 Emscripten (调整下电脑的休眠时间,不要让电脑进入休眠,安装时间较长)

安装步骤如下:

git clone https://github.com/juj/emsdk.git

cd emsdk

./emsdk install --build=Release sdk-incoming-64bit binaryen-master-64bit

./emsdk activate --global --build=Release sdk-incoming

    -64bit binaryen-master-64bit

执行 source ./emsdk_env.sh,并将shell中的内容添加到环境变量中(~/.bash_profile):

执行: source ~/.bash_profile

4.安装 WABT(将.wast文件转成 .wasm文件)

git clone https://github.com/WebAssembly/wabt.git

cd wabt

make install gcc-release

5.浏览器设置

Chrome: 打开 chrome://flags/#enable-webassembly,选择 enable。

Firefox: 打开 about:config 将 javascript.options.wasm 设置为 true。

如果浏览器太旧,请更新浏览器,或者安装激进版浏览器来体验新技术。

6.一个本地web服务器.

Emscripten,它基于 LLVM ,可以将 C/C++ 编译成 asm.js,使用 WASM 标志也可以直接生成 WebAssembly 二进制文件(后缀是 .wasm)

俄罗斯贵宾会 5

         Emscripten

source.c   ----->  target.js



     Emscripten (with flag)

source.c   ----->  target.wasm

注:emcc 在 1.37 以上版本才支持直接生成 wasm 文件

Binaryen 是一套更为全面的工具链,是用C++编写成用于WebAssembly的编译器和工具链基础结构库。WebAssembly是二进制格式(Binary Format)并且和Emscripten集成,因此该工具以Binary和Emscript-en的末尾合并命名为Binaryen。它旨在使编译WebAssembly容易、快速、有效。

俄罗斯贵宾会 6

wasm-as:将WebAssembly由文本格式编译成二进制格式; wasm-dis:将二进制格式的WebAssembly反编译成文本格式; asm2wasm:将asm.js编译到WebAssembly文本格式,使用Emscripten的asm优化器; s2wasm:在LLVM中开发,由新WebAssembly后端产生的.s格式的编译器; wasm.js:包含编译为JavaScript的Binaryen组件,包括解释器、asm2wasm、S表达式解析器等。

WABT工具包支持将二进制WebAssembly格式转换为可读的文本格式。其中wasm2wast命令行工具可以将WebAssembly二进制文件转换为可读的S表达式文本文件。而wast2wasm命令行工具则执行完全相反的过程。

wat2wasm: webAssembly文本格式转换为webAssembly二进制格式(.wast 到 .wasm) wasm2wat: 将WebAssembly二进制文件转换为可读的S表达式文本文件(.wat) wasm-objdump: print information about a wasm binary. Similiar to objdump. wasm-interp: 基于堆栈式解释器解码和运行webAssembly二进制文件 wat-desugar: parse .wat text form as supported by the spec interpreter wasm-link: simple linker for merging multiple wasm files. wasm2c: 将webAssembly二进制文件转换为C的源文件

平台接口访问

依赖于执行 JavaScript 的运行时环境,可以通过 JavaScript 程序来直接访问这些平台所暴露出的指定接口。比如,当你在浏览器中运行 JavaScript,网络应用可以调用一系列的网页接口来控制浏览器/设备的功能且访问 DOMCSSOMWebGLIndexedDBWeb Audio API 等等。

然而,WebAssembly 模块不能够访问任何平台的接口。所有的这一切都得由 JavaScript 来进行协调。如果你想在 WebAssembly 模块内访问一些指定平台的接口,你必须得通过 JavaScript 来进行调用。

举个栗子,如果你想要使用 console.log,你就得通过JavaScript 而不是 C++ 代码来进行调用。而这些 JavaScript 调用会产生一定的性能损失。

情况不会一成不变的。规范将会为在未来为 wasm 提供访问指定平台的接口,这样你就可以不用在你的程序中内置 JavaScript。

webAssembly.Module

WebAssembly.Module() 构造函数可以用来同步编译给定的 WebAssembly 二进制代码。不过,获取 Module 对象的主要方法是通过异步编译函数,如 WebAssembly.compile(),或者是通过 IndexedDB 读取 Module 对象.

var myInstance = new WebAssembly.Instance(module, importObject);

module: 需要被实例化的webAssembly module importObject: 需要导入的变量

首先,认识下 WebAssembly 吧

WebAssembly(又称 wasm) 是一种用于开发网络应用的高效,底层的字节码。

WASM 让你在其中使用除 JavaScript 的语言以外的语言(比如 C, C++, Rust 及其它)来编写应用程序,然后编译成(提早) WebAssembly。

构建出来的网络应用加载和运行速度都会非常快。

未来功能

直接操作DOM 支持多数据(SIMD):SIMD的使用可以获取大的数据结构,例如不同数目的向量,并且同时将相同的指令应用于不同的部分。这样,它可以大大加快各种复杂计算的游戏或VR的运行速度。 ES6模块集成:浏览器目前正在添加对使用script标签加载JavaScript模块的支持。 添加此功能后,即使URL指向WebAssembly模块, <

本文由俄罗斯贵宾会发布于Web前端,转载请注明出处:WebAssembly 对比 JavaScript 及其使用场景

您可能还会对下面的文章感兴趣: