本文轉載自:衆成翻譯
譯者:文藺
連接:http://www.zcfy.cc/article/1031
原文:http://cultureofdevelopment.com/blog/build-your-first-thing-with-web-assemblyjavascript
拖拖拉拉很久,終於把我的博客整出來了。鳴謝 @pinggod。厚着臉安利一下,地址是 http://www.wemlion.com/。歡迎訪問,歡迎收藏。html
頭一次據說 WebAssembly 的時候就以爲很酷,而後就超興奮地開始嘗試。但從一開始嘗試的過程就不順利,愈來愈讓人灰心。本文的目的就是解決問題,讓你免受困擾。java
本文寫做於 2016 年 6 月 24 日。WebAssembly 是一項很新的、不穩定的技術;隨着其標準化過程發展,本文中的任何內容均可能是錯誤的。git
不過先無論了....github
好吧,官網是這麼描述的:web
WebAssembly,或者稱做 wasm,是一項適用於 Web 編譯的可移植的、體積與加載高效的格式。(WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.)chrome
嗯...什麼鬼?什麼格式?文本(Text)?二進制(Binary)?老實說,這個描述真糟糕。因此無論它,收起那些 binggo 遊戲卡(buzzword bingo cards,一種填詞遊戲,這些詞一般都是流行語,閱讀https://en.wikipedia.org/wiki/Buzzword_bingo瞭解更多 —— 譯者注),根據我全部的經驗來描述吧:npm
WebAssembly/wasm 是用來編寫高性能的、瀏覽器無關的 Web 組件的一種字節碼規範。(WebAssembly or wasm is a bytecode specification for writing performant, browser agnostic web components.)數組
有此妙語,聽起來超棒,但仍然沒 get 到點,接下來重點來了。WebAssembly 經過靜態類型變量實現性能提高,運行時靜態類型變量引用比動態類型變量更有效率。WebAssembly 由 W3C Community Group 制定,最終將被全部規範兼容的瀏覽器支持。還有殺手鐗,最終咱們可使用任何語言編寫這些 Web 組件(web components)。瀏覽器
聽起來酷了不少,不是麼?
學習新東西的時候,我一般會找儘量最簡單的例子來看它是如何工做的。不幸的是,對 WebAssembly 來講,這不太現實。在當前階段,wasm 僅僅只是字節碼規範。想象回到 1996 年,假如太陽公司(Sun Microsystems)的一些工程師們帶來了 JVM,但卻...沒有 Java....若果然如此,我想當時的對話多是這樣的:
—— 「夥計們,快來看看咱們作的這個執行字節碼的虛擬機!」
—— 「真棒!但咱們給它怎麼寫代碼?」
圖:字節碼形式的 HelloWorld
—— 「嗯..這問題提得好。等會兒我查查看。」
—— 「真棒,若是遇到了任何問題,告訴咱們你的想法,在咱們的 github page 上貼出來。」
—— 「你說對啦。咱們如今先去看看其餘項目。」
這個例子有些糟糕,由於 JVM 是基於 Java 語言的;儘管如此,但願你仍是 get 到點了。若是都沒有將代碼編譯爲字節碼的工具,要起步就很困難了。那咱們要怎麼開始?
多數技術都是創新的結果,特別是當合理的嘗試成爲正式規範時。wasm 也不例外,它其實是 asm.js 的工做的延續, asm.js 是一個編寫 javascript 組件的的規範,可編譯爲靜態類型。wasm 的規範拓展了這些創意,它接受任何語言編譯而成的字節碼,這些字節碼做爲二進制文件而非文本文件經過網絡傳輸;規範由不少來自主流瀏覽器廠商的表明們一塊兒制定,而非僅僅是 Mozilla。
asm.js 僅僅是一個使用 javascript 語言特徵的最小子集編寫 javascript 的規範。你能夠手寫一些簡單的 asm.js 代碼,若是你想弄髒你的手,這正是極好的方式。(等會兒最好將這放在單獨的文件中,一般約定文件名格式爲 your-module-name.asm.js
。))
function MyMathModule(global) { "use asm"; var exp = global.Math.exp; function doubleExp(value) { value = +value; return +(+exp(+value) * 2.0); } return { doubleExp: doubleExp }; }
這還不是一個特別有用的函數,但符合規範。若是你以爲這很二,別人也是這麼以爲的,不過基本上每個字符都是必須的。在這當中,一元運算符 +
的做用是類型註解,這樣編譯器會知道那些變量是 double 類型的,運行時就沒必要再次分辨它們是什麼。它至關挑剔,若是你把什麼地方弄得一團糟,火狐控制檯會給你一些合理的錯誤信息。
若是你想在瀏覽器中使用,像下面這樣:
var myMath = new MyMathModule(window); for(var i = 0; i < 5; i++) { console.log(myMath.doubleExp(i)); }
一切正常的話,結果大概像下圖這樣:
如今咱們已經有了一個能夠工做的 asm.js 代碼片斷,可使用 WebAssembly github page 提供的工具將其編譯爲 wasm。本身克隆代碼倉庫構建工具吧。這最麻煩了。這些工具一直在不斷髮展,代碼會時不時掛掉,特別是在 Windows 環境下。
無論你是用 Windows 仍是 Mac,電腦上必需要安裝 make 和 cmake 命令行工具。若是你在使用 Windows,你還須要安裝 Visual Studio 2015。Mac 用戶按照這裏的說明 操做;Windows 用戶按照這個說明操做。
圖: Windows 下的工具構建
對 WebAssembly 團隊來講,發佈能夠工做的二進制文件意味着朝着正確的方向前進了一大步。
構建成功以後,binaryen 目錄下會有一個 bin 文件夾,其中有一些用來將 asm.js 轉換爲 wasm 的工具。第一個工具是 asm2wasm.exe
。它將 asm.js 代碼轉換爲 .s
格式的代碼,這些代碼是生成 wasm 所需的抽象語法樹(AST)的文本表現形式。運行工具,最終會獲得相似下面的東西:
(module (memory 256 256) (export "memory" memory) (type $FUNCSIG$dd (func (param f64) (result f64))) (import $exp "global.Math" "exp" (param f64) (result f64)) (export "doubleExp" $doubleExp) (func $doubleExp (param $0 f64) (result f64) (f64.mul (call_import $exp (get_local $0) ) (f64.const 2) ) ) )
之後咱們能夠逐行分析上面的代碼,但如今我只想讓你看下它的樣子。我還得提醒你一點,由於 wasm 是二進制格式的,因此像你今天對 javascript 所作的那樣右擊、查看源碼是行不通的。從頭至尾都是二進制碼。目前的計劃是查看 wasm 模塊源碼時對二進制格式進行反彙編,讓人能讀懂。
接下來要作的是使用 wasm-as.exe
將 .s
格式的代碼轉換爲 wasm 二進制碼。運行文件,最後就能獲得瀏覽器須要的真正的 wasm 二進制碼。
圖:將 asm.js 轉換爲 wasm 二進制碼
圖:wasm 二進制碼
緊接着,安裝最新版的 Firefox 或 Chrome Canary,並啓用 WebAssembly。
若是你使用的是 Firefox,在地址欄中輸入 about:config
,點擊「確認我會保證當心」。而後在搜索框中輸入 wasm
,雙擊 javascript.options.wasm
將值設置爲 true,而後重啓瀏覽器。
若是你使用的是 Chrome Canary,打開 chrome://flags
,往下翻,找到 Experimental WebAssembly
,點擊「啓用」連接,再重啓瀏覽器。
最後一步就是讓模塊在瀏覽器中跑起來。初次嘗試時,這又是一大痛點,徹底不知道怎麼作。在規範中使用 wasm 模塊的 API 一點都沒找到。最後我在 Canary 的控制檯上輸入 WebAsse
,並無任何提示。接着輸入 Was
的時候,提示出來了!控制檯上打印出的對象大概最簡陋的文檔了,不過這時候我忽然想到,能夠用一些其餘工具 (emscripten) 將代碼編譯爲 wasm。不過這是另一篇博客的話題了。
一段時間以後,鼠標落在了 WebAssembly 的設計文檔倉庫上。我看到了一個名爲 JS.md 的文件,點擊以後,有一個 API 的說明。仔細看頂部斜體的文字。但最精彩的部分仍是最底部的代碼片斷,演示瞭如何最低限度地加載模塊。我所須要作的就是拆出相關部分進行嘗試。
fetch("my-math-module.wasm") .then(function(response) { return response.arrayBuffer(); }) .then(function(buffer) { var dependencies = { "global": {}, "env": {} }; dependencies["global.Math"] = window.Math; var moduleBufferView = new Uint8Array(buffer); var myMathModule = Wasm.instantiateModule(moduleBufferView, dependencies); console.log(myMathModule.exports.doubleExp); for(var i = 0; i < 5; i++) { console.log(myMathModule.exports.doubleExp(i)); } });
把代碼放到 html 文件中,啓動本地文件服務器,在瀏覽器中加載頁面。下面是在瀏覽器中的結果:
瀏覽器中運行的 wasm (至少嘗試運行了)
我估計須要去提交一個 bug 報告了。記着,一切都是實驗性的、不穩定的,因此當此類事情發生的時候,別灰心喪氣。
你已經完成了第一個 WebAssembly 組件。接下來作些什麼?目前咱們碰到的還只是皮毛而已。在本例中手寫 asm.js 很重要,但須要時間和耐心。使用 emscripten 將應用轉換爲 asm.js 要簡單多了。關於這一點,我強烈建議你閱讀 asm.js 規範,特別是內存模型的部分,由於其中的許多概念都被遷移到 WebAssembly 上了。另一個怪異的事情是,目前還不能直接將數組做爲函數參數。人們已經達成共識,這須要改變,但規範中還沒有有關於這一點的。去看看指針邏輯吧。
還有一點,在 wasm 中作一些工做的時候,你可能發展實際上 WebAssembly 還沒普通的 javascript 運行得快。記住,現代的 javascript 引擎已是高度優化的,wasm 要遇上這速度還須要時間。WebAssembly 還還沒有進入準備生產的階段。
若是你有任何關於 wasm 或者本文中提到的工具的問題,在 Stack Overflow 中提出來,記得標上恰當的 tag。