破晓 发表于 2016-8-18 16:55:59

WebAssembly 初尝

来源:http://www.zcfy.cc/article/build-your-first-thing-with-webassembly-culture-of-development-1031.html<p></p><div><br></div><div><span style="color: rgb(153, 153, 153); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; font-size: 12px; line-height: 18px;">原文链接:</span><a target="_blank" href="http://cultureofdevelopment.com/blog/build-your-first-thing-with-web-assembly" style="text-decoration: none; color: rgb(74, 197, 206); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; font-size: 12px; line-height: 18px;">&nbsp;http://cultureofdevelopment.com/blog/build-your-first-thing-with-web-assembly</a></div><div><br></div><div><div class="translation" style="font-size: 16px; color: rgb(51, 51, 51); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; line-height: 28px; width: 896.5px;"><p style="margin-bottom: 1em;">头一次听说&nbsp;<a href="https://webassembly.github.io/" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">WebAssembly</a>&nbsp;的时候就觉得很酷,然后就超兴奋地开始尝试。但从一开始尝试的过程就不顺利,越来越让人灰心。本文的目的就是解决问题,让你免受困扰。</p><p style="margin-bottom: 1em;"><img src="http://p4.qhmsg.com/t014315b7ee6ed04cb7.jpg" alt="beware of cliff" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><h3 id="-" style="margin-bottom: 10px; font-size: 18px;">读者须知</h3><p style="margin-bottom: 1em;">本文写作于 2016 年 6 月 24 日。WebAssembly 是一项很新的、不稳定的技术;随着其标准化过程发展,本文中的任何内容都可能是错误的。</p><p style="margin-bottom: 1em;">不过先不管了....</p><h3 id="webassembly-" style="margin-bottom: 10px; font-size: 18px;">WebAssembly 是什么</h3><p style="margin-bottom: 1em;">好吧,官网是这么描述的:</p><blockquote style="margin-bottom: 15px; padding-left: 15px; border-left-width: 5px; border-left-style: solid; border-left-color: rgb(221, 221, 221); color: rgb(102, 102, 102); font-size: 14px; font-style: italic;"><p style="margin-bottom: 1em;">WebAssembly,或者称作 wasm,是一项适用于 Web 编译的可移植的、体积与加载高效的格式。(WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.)</p></blockquote><p style="margin-bottom: 1em;">嗯...什么鬼?什么格式?文本(Text)?二进制(Binary)?老实说,这个描述真糟糕。所以不管它,收起那些 binggo 游戏卡(buzzword bingo cards,一种填词游戏,这些词通常都是流行语,阅读<a href="https://en.wikipedia.org/wiki/Buzzword_bingo" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">https://en.wikipedia.org/wiki/Buzzword_bingo</a>了解更多 —— 译者注),根据我所有的经验来描述吧:</p><blockquote style="margin-bottom: 15px; padding-left: 15px; border-left-width: 5px; border-left-style: solid; border-left-color: rgb(221, 221, 221); color: rgb(102, 102, 102); font-size: 14px; font-style: italic;"><p style="margin-bottom: 1em;">WebAssembly/wasm 是用来编写高性能的、浏览器无关的 Web 组件的一种字节码规范。(WebAssembly or wasm is a bytecode specification for writing performant, browser agnostic web components.)</p></blockquote><p style="margin-bottom: 1em;">有此妙语,听起来超棒,但仍然没 get 到点,接下来重点来了。WebAssembly 通过静态类型变量实现性能提升,运行时静态类型变量引用比动态类型变量更有效率。WebAssembly 由&nbsp;<a href="https://www.w3.org/community/webassembly/" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">W3C Community Group</a>&nbsp;制定,最终将被所有规范兼容的浏览器支持。还有杀手锏,<em>最终</em>我们可以使用<em>任何</em>语言编写这些 Web 组件(web components)。</p><p style="margin-bottom: 1em;">听起来酷了很多,不是么?</p><h3 id="-" style="margin-bottom: 10px; font-size: 18px;">一起开始吧</h3><p style="margin-bottom: 1em;">学习新东西的时候,我通常会找尽可能最简单的例子来看它是如何工作的。不幸的是,对 WebAssembly 来说,这不太现实。在当前阶段,wasm 仅仅只是字节码规范。想象回到 1996 年,假如太阳公司(Sun Microsystems)的一些工程师们带来了 JVM,但却...没有 Java....若果真如此,我想当时的对话可能是这样的:</p><p style="margin-bottom: 1em;">—— “伙计们,快来看看我们做的这个执行字节码的虚拟机!” —— “真棒!但我们给它怎么写代码?”</p><p style="margin-bottom: 1em;"><img src="http://p1.qhmsg.com/t01c5889a9cdf0ef479.png" alt="HelloWorld.class" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><p style="margin-bottom: 1em;"><em>图:字节码形式的 HelloWorld</em></p><p style="margin-bottom: 1em;">—— “嗯..这问题提得好。等会儿我查查看。” —— “真棒,如果遇到了任何问题,告诉我们你的想法,在我们的 github page 上贴出来。” —— “你说对啦。我们现在先去看看其他项目。”</p><p style="margin-bottom: 1em;">这个例子有些糟糕,因为 JVM 是基于 Java 语言的;尽管如此,希望你还是 get 到点了。如果都没有将代码编译为字节码的工具,要起步就很困难了。那我们要怎么开始?</p><h3 id="webassembly-" style="margin-bottom: 10px; font-size: 18px;">WebAssembly 之前有什么</h3><p style="margin-bottom: 1em;">多数技术都是创新的结果,特别是当合理的尝试成为正式规范时。wasm 也不例外,它实际上是&nbsp;<a href="http://asmjs.org/" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">asm.js</a>&nbsp;的工作的延续, asm.js 是一个编写 javascript 组件的的规范,可编译为静态类型。wasm 的规范拓展了这些创意,它接受任何语言编译而成的字节码,这些字节码作为二进制文件而非文本文件通过网络传输;规范由很多来自主流浏览器厂商的代表们一起制定,而非仅仅是 Mozilla。</p><p style="margin-bottom: 1em;">asm.js 仅仅是一个使用 javascript 语言特征的最小子集编写 javascript 的规范。你可以手写一些简单的 asm.js 代码,如果你想弄脏你的手,这正是极好的方式。(等会儿最好将这放在单独的文件中,通常约定文件名格式为&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">your-module-name.asm.js</code>。))</p><pre class="prettyprint prettyprinted" style="margin-bottom: 15px; padding: 10px; border: 1px solid rgb(221, 221, 221); border-radius: 3px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; font-size: 12px; white-space: pre-wrap; overflow: auto; background: padding-box padding-box rgb(248, 248, 248);"><code style="border: none; border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-image: initial; background-attachment: initial; background-size: initial; background-origin: padding-box; background-clip: padding-box; background-position: initial; background-repeat: initial;"><span class="kwd" style="color: rgb(0, 0, 136);">function</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MyMathModule</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">global</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="str" style="color: rgb(0, 136, 0);">"use asm"</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> exp </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">global</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">Math</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">exp</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">function</span><span class="pln" style="color: rgb(0, 0, 0);"> doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">value</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
      value </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">+</span><span class="pln" style="color: rgb(0, 0, 0);">value</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">+(+</span><span class="pln" style="color: rgb(0, 0, 0);">exp</span><span class="pun" style="color: rgb(102, 102, 0);">(+</span><span class="pln" style="color: rgb(0, 0, 0);">value</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">*</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">2.0</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);"> doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> doubleExp </span><span class="pun" style="color: rgb(102, 102, 0);">};</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span></code></pre><p style="margin-bottom: 1em;">这还不是一个特别有用的函数,但符合规范。如果你觉得这很二,别人也是这么觉得的,不过基本上每一个字符都是必须的。在这当中,一元运算符&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">+</code>&nbsp;的作用是类型注解,这样编译器会知道那些变量是 double 类型的,运行时就不必再次分辨它们是什么。它相当挑剔,如果你把什么地方弄得一团糟,火狐控制台会给你一些合理的错误信息。</p><p style="margin-bottom: 1em;">如果你想在浏览器中使用,像下面这样:</p><pre class="prettyprint prettyprinted" style="margin-bottom: 15px; padding: 10px; border: 1px solid rgb(221, 221, 221); border-radius: 3px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; font-size: 12px; white-space: pre-wrap; overflow: auto; background: padding-box padding-box rgb(248, 248, 248);"><code style="border: none; border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-image: initial; background-attachment: initial; background-size: initial; background-origin: padding-box; background-clip: padding-box; background-position: initial; background-repeat: initial;"><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> myMath </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">MyMathModule</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">window</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="kwd" style="color: rgb(0, 0, 136);">for</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> i </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"> i </span><span class="pun" style="color: rgb(102, 102, 0);">&lt;</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">5</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"> i</span><span class="pun" style="color: rgb(102, 102, 0);">++)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
    console</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">log</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">myMath</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">i</span><span class="pun" style="color: rgb(102, 102, 0);">));</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">}</span></code></pre><p style="margin-bottom: 1em;">一切正常的话,结果大概像下图这样:</p><p style="margin-bottom: 1em;"><img src="http://p6.qhmsg.com/t01d27d8a53bcd3c767.png" alt="asm.js success" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><h3 id="-webassembly" style="margin-bottom: 10px; font-size: 18px;">开始尝试 WebAssembly</h3><p style="margin-bottom: 1em;">现在我们已经有了一个可以工作的 asm.js 代码片段,可以使用&nbsp;<a href="https://github.com/WebAssembly/binaryen" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">WebAssembly github page</a>&nbsp;提供的工具将其编译为 wasm。自己克隆代码仓库构建工具吧。这最麻烦了。这些工具一直在不断发展,代码会时不时挂掉,特别是在 Windows 环境下。</p><p style="margin-bottom: 1em;">不管你是用 Windows 还是 Mac,电脑上必须要安装 make 和 cmake 命令行工具。如果你在使用 Windows,你还需要安装 Visual Studio 2015。Mac 用户按照<a href="https://github.com/WebAssembly/binaryen#building" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">这里的说明</a>&nbsp;操作;Windows 用户按照<a href="https://github.com/brakmic/brakmic/blob/master/webassembly/COMPILING_WIN32.md" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">这个说明</a>操作。</p><p style="margin-bottom: 1em;"><img src="http://p8.qhmsg.com/t01f65f188a46e3d538.png" alt="building binaryen" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><p style="margin-bottom: 1em;"><em>图: Windows 下的工具构建</em></p><p style="margin-bottom: 1em;">对 WebAssembly 团队来说,发布可以工作的二进制文件意味着朝着正确的方向前进了一大步。</p><p style="margin-bottom: 1em;">构建成功之后,binaryen 目录下会有一个 bin 文件夹,其中有一些用来将 asm.js 转换为 wasm 的工具。第一个工具是<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">asm2wasm.exe</code>。它将 asm.js 代码转换为&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">.s</code>&nbsp;格式的代码,这些代码是生成 wasm 所需的抽象语法树(AST)的文本表现形式。运行工具,最终会得到类似下面的东西:</p><pre class="prettyprint prettyprinted" style="margin-bottom: 15px; padding: 10px; border: 1px solid rgb(221, 221, 221); border-radius: 3px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; font-size: 12px; white-space: pre-wrap; overflow: auto; background: padding-box padding-box rgb(248, 248, 248);"><code style="border: none; border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-image: initial; background-attachment: initial; background-size: initial; background-origin: padding-box; background-clip: padding-box; background-position: initial; background-repeat: initial;"><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">module</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">memory </span><span class="lit" style="color: rgb(0, 102, 102);">256</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">256</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">export</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(0, 136, 0);">"memory"</span><span class="pln" style="color: rgb(0, 0, 0);"> memory</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">type $FUNCSIG$dd </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">func </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">param f64</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">result f64</span><span class="pun" style="color: rgb(102, 102, 0);">)))</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">import</span><span class="pln" style="color: rgb(0, 0, 0);"> $exp </span><span class="str" style="color: rgb(0, 136, 0);">"global.Math"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(0, 136, 0);">"exp"</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">param f64</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">result f64</span><span class="pun" style="color: rgb(102, 102, 0);">))</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">export</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="str" style="color: rgb(0, 136, 0);">"doubleExp"</span><span class="pln" style="color: rgb(0, 0, 0);"> $doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">func $doubleExp </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">param $0 f64</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">result f64</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">f64</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">mul
      </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">call_import $exp
      </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">get_local $0</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">f64</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="kwd" style="color: rgb(0, 0, 136);">const</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">2</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
</span><span class="pun" style="color: rgb(102, 102, 0);">)</span></code></pre><p style="margin-bottom: 1em;">以后我们可以逐行分析上面的代码,但现在我只想让你看下它的样子。我还得提醒你一点,因为 wasm 是二进制格式的,所以像你今天对 javascript 所做的那样右击、查看源码是行不通的。从头到尾都是二进制码。目前的计划是查看 wasm 模块源码时对二进制格式进行反汇编,让人能读懂。</p><p style="margin-bottom: 1em;">接下来要做的是使用&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">wasm-as.exe</code>&nbsp;将&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">.s</code>&nbsp;格式的代码转换为 wasm 二进制码。运行文件,最后就能得到浏览器需要的真正的 wasm 二进制码。</p><p style="margin-bottom: 1em;"><img src="http://cultureofdevelopment.com/img/binaryen-transform.png" alt="building wasm from asm.js" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><p style="margin-bottom: 1em;"><em>图:将 asm.js 转换为 wasm 二进制码</em></p><p style="margin-bottom: 1em;"><img src="http://p6.qhmsg.com/t01a5965c1d53b30e20.png" alt="wasm bytecode" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><p style="margin-bottom: 1em;"><em>图:wasm 二进制码</em></p><p style="margin-bottom: 1em;">紧接着,安装最新版的&nbsp;<a href="https://www.mozilla.org/en-US/firefox/new/" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">Firefox</a>&nbsp;或&nbsp;<a href="https://www.google.com/chrome/browser/canary.html" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">Chrome Canary</a>,并启用 WebAssembly。</p><p style="margin-bottom: 1em;">如果你使用的是 Firefox,在地址栏中输入&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">about:config</code>,点击“确认我会保证小心”。然后在搜索框中输入&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">wasm</code>,双击<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">javascript.options.wasm</code>&nbsp;将值设置为 true,然后重启浏览器。</p><p style="margin-bottom: 1em;">如果你使用的是 Chrome Canary,打开&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">chrome://flags</code>,往下翻,找到&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">Experimental WebAssembly</code>,点击“启用”链接,再重启浏览器。</p><p style="margin-bottom: 1em;">最后一步就是让模块在浏览器中跑起来。初次尝试时,这又是一大痛点,完全不知道怎么做。在规范中使用 wasm 模块的 API 一点都没找到。最后我在 Canary 的控制台上输入&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">WebAsse</code>,并没有任何提示。接着输入&nbsp;<code style="margin-right: 4px; margin-left: 5px; padding: 2px 5px; border: 1px solid rgb(234, 234, 234); border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; background: padding-box padding-box rgb(248, 248, 248);">Was</code>&nbsp;的时候,提示出来了!控制台上打印出的对象大概最简陋的文档了,不过这时候我突然想到,可以用一些其他工具 (emscripten) 将代码编译为 wasm。不过这是另外一篇博客的话题了。</p><p style="margin-bottom: 1em;">一段时间之后,鼠标落在了 WebAssembly 的设计文档仓库上。我看到了一个名为&nbsp;<a href="https://github.com/WebAssembly/design/blob/master/JS.md" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">JS.md</a>&nbsp;的文件,点击之后,有一个 API 的说明。仔细看顶部斜体的文字。但最精彩的部分还是最底部的代码片段,演示了如何最低限度地加载模块。我所需要做的就是拆出相关部分进行尝试。</p><pre class="prettyprint prettyprinted" style="margin-bottom: 15px; padding: 10px; border: 1px solid rgb(221, 221, 221); border-radius: 3px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; line-height: 18px; font-size: 12px; white-space: pre-wrap; overflow: auto; background: padding-box padding-box rgb(248, 248, 248);"><code style="border: none; border-radius: 3px; font-size: 14px; font-family: &quot;YaHei Consolas Hybrid&quot;, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; white-space: pre; background-image: initial; background-attachment: initial; background-size: initial; background-origin: padding-box; background-clip: padding-box; background-position: initial; background-repeat: initial;"><span class="pln" style="color: rgb(0, 0, 0);">fetch</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="str" style="color: rgb(0, 136, 0);">"my-math-module.wasm"</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="kwd" style="color: rgb(0, 0, 136);">then</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">function</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">response</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">return</span><span class="pln" style="color: rgb(0, 0, 0);"> response</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">arrayBuffer</span><span class="pun" style="color: rgb(102, 102, 0);">();</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">})</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="kwd" style="color: rgb(0, 0, 136);">then</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">function</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">buffer</span><span class="pun" style="color: rgb(102, 102, 0);">)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> dependencies </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="str" style="color: rgb(0, 136, 0);">"global"</span><span class="pun" style="color: rgb(102, 102, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{},</span><span class="pln" style="color: rgb(0, 0, 0);">
            </span><span class="str" style="color: rgb(0, 136, 0);">"env"</span><span class="pun" style="color: rgb(102, 102, 0);">:</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{}</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="pun" style="color: rgb(102, 102, 0);">};</span><span class="pln" style="color: rgb(0, 0, 0);">
      dependencies</span><span class="pun" style="color: rgb(102, 102, 0);">[</span><span class="str" style="color: rgb(0, 136, 0);">"global.Math"</span><span class="pun" style="color: rgb(102, 102, 0);">]</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> window</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="typ" style="color: rgb(102, 0, 102);">Math</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> moduleBufferView </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="kwd" style="color: rgb(0, 0, 136);">new</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Uint8Array</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">buffer</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> myMathModule </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="typ" style="color: rgb(102, 0, 102);">Wasm</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">instantiateModule</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">moduleBufferView</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> dependencies</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
      console</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">log</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">myMathModule</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">exports</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="kwd" style="color: rgb(0, 0, 136);">for</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="kwd" style="color: rgb(0, 0, 136);">var</span><span class="pln" style="color: rgb(0, 0, 0);"> i </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"> i </span><span class="pun" style="color: rgb(102, 102, 0);">&lt;</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">5</span><span class="pun" style="color: rgb(102, 102, 0);">;</span><span class="pln" style="color: rgb(0, 0, 0);"> i</span><span class="pun" style="color: rgb(102, 102, 0);">++)</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="pun" style="color: rgb(102, 102, 0);">{</span><span class="pln" style="color: rgb(0, 0, 0);">
            console</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">log</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">myMathModule</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">exports</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">doubleExp</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="pln" style="color: rgb(0, 0, 0);">i</span><span class="pun" style="color: rgb(102, 102, 0);">));</span><span class="pln" style="color: rgb(0, 0, 0);">
      </span><span class="pun" style="color: rgb(102, 102, 0);">}</span><span class="pln" style="color: rgb(0, 0, 0);">
    </span><span class="pun" style="color: rgb(102, 102, 0);">});</span></code></pre><p style="margin-bottom: 1em;">把代码放到 html 文件中,<a href="https://www.npmjs.com/package/local-web-server" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">启动本地文件服务器</a>,在浏览器中加载页面。下面是在浏览器中的结果:</p><p style="margin-bottom: 1em;"><img src="http://p8.qhmsg.com/t01631e5f7d290aae84.png" alt="wasm in a browser" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><p style="margin-bottom: 1em;"><em>浏览器中运行的 wasm (至少尝试运行了)</em></p><p style="margin-bottom: 1em;">我估计需要去提交一个 bug 报告了。记着,一切都是实验性的、不稳定的,所以当此类事情发生的时候,别灰心丧气。</p><p style="margin-bottom: 1em;"><img src="http://p3.qhmsg.com/t017618b22a564ebf7f.png" alt="keep calm and file bug reports" style="border: none; outline: 0px; vertical-align: middle; max-width: 100%;"></p><h3 id="-" style="margin-bottom: 10px; font-size: 18px;">恭喜你</h3><p style="margin-bottom: 1em;">你已经完成了第一个 WebAssembly 组件。接下来做些什么?目前我们碰到的还只是皮毛而已。在本例中手写 asm.js 很重要,但需要时间和耐心。使用 emscripten 将应用转换为 asm.js 要简单多了。关于这一点,我强烈建议你阅读 asm.js 规范,特别是内存模型的部分,因为其中的许多概念都被迁移到 WebAssembly 上了。另外一个怪异的事情是,目前还不能直接将数组作为函数参数。人们已经达成共识,这需要改变,但规范中尚未有关于这一点的。去看看指针逻辑吧。</p><p style="margin-bottom: 1em;">还有一点,在 wasm 中做一些工作的时候,你可能发展实际上 WebAssembly 还没普通的 javascript 运行得快。记住,现代的 javascript 引擎已经是高度优化的,wasm 要赶上这速度还需要时间。WebAssembly 还尚未进入准备生产的阶段。</p><p style="margin-bottom: 1em;">如果你有任何关于 wasm 或者本文中提到的工具的问题,在&nbsp;<a href="http://stackoverflow.com/" style="text-decoration: none; color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">Stack Overflow</a>&nbsp;中提出来,记得标上恰当的 tag。</p></div><span class="clearfix" style="color: rgb(51, 51, 51); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; line-height: 28px;"></span><span style="color: rgb(51, 51, 51); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; line-height: 28px;"></span><div id="copyright" class="" style="padding: 1em; color: rgb(51, 51, 51); font-family: &quot;HanHei SC&quot;, &quot;PingFang SC&quot;, &quot;Lantinghei SC&quot;, arial, &quot;Microsoft Yahei&quot;, georgia, verdana, helvetica, sans-serif; line-height: 28px; background: rgb(239, 239, 239);"><h2 class="title" style="margin-bottom: 10px; font-weight: 400; line-height: 40px;">版权声明</h2><div class="content">本译文仅用于学习、研究和交流目的,欢迎非商业转载。转载请注明出处、译者和众成翻译的完整链接。要获取包含以上信息的本文Markdown源文本,请<a class="get-markdown" href="http://www.zcfy.cc/api/getarticlemarkdown?id=1031" target="_blank" style="color: rgb(74, 197, 206); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: rgb(229, 229, 229);">点击这里</a>。</div></div></div>

我是一个兵 发表于 2016-8-18 17:21:02

不错,学习了

水玲珑 发表于 2016-8-18 17:37:35

学习一下........
页: [1]
查看完整版本: WebAssembly 初尝