轉載自:www.blog.csdn.net/sinat_32582203/article/details/73355211
WebAssembly作為一種新興的Web技術,相關的資料和社區還不夠豐富,但其為web開發提供了一種嶄新的思路和工作方式,未來是很有可能大放光彩的。
使用WebAssembly,我們可以在瀏覽器中運行一些高性能、低級別的程式語言,可用它將大型的C和C++代碼庫比如遊戲、物理引擎甚至是桌面應用程式導入Web平臺。
截至目前為止,我們已經可以在Chrome、Firefox中使用WebAssembly,Edge和Safari對它的支持也基本完成。這意味著很快,就能在所有流行的瀏覽器中運行wasm了。
在這篇文章中,我們將會演示如何將簡單的C代碼編譯為wasm,並將其包含在網頁中。在此之前,我們先來直觀的了解下WebAssembly是如何工作的。
WebAssembly是如何工作的?
這裡不涉及過多技術性的問題。我們知道,在今天的瀏覽器中,JavaScript是在虛擬機(VM)中執行的,該虛擬機能夠最大化地優化代碼並壓榨每一絲的性能,這也使得JavaScript稱為速度最快的動態語言之一。但儘管如此,它還是無法與原生的C/C++代碼相媲美。所以,WebAssembly就出現了。
Wasm同樣在JavaScript虛擬機中運行,但是它表現得更好。兩者可以自由交互、互不排斥,這樣你就同時擁有了兩者最大的優勢——JavaScript巨大的生態系統和有好的語法,WebAssembly接近原生的表現性能。
大多數程式設計師會選擇使用C語言來編寫WebAssembly模塊,並將其編譯成.wasm文件。這些.wasm文件並不能直接被瀏覽器識別,所以它們需要一種稱為JavaScript膠接代碼(glue code,用於連接相互不兼容的軟體組件,詳見:http://whatis.techtarget.com/definition/glue-code)的東西來加載。
隨著未來WebAssembly框架和本地wasm模塊支持的發展,這一過程可能會有所縮短。
開發前準備
編寫WebAssembly需要不少的工具,但作為一個程式設計師,下面的工具你應該大部分都已經有了。
1、支持WebAssembly的瀏覽器,新版的Chrome或者Firefox均可(可以在此查看各個瀏覽器對某項內容的支持情況:http://caniuse.com/#feat=wasm)。
2、C到WebAssembly的編譯器,推薦使用Emscripten(https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html),安裝這個工具費時費力費空間,但沒辦法,這是目前為止最好的選擇,請仔細閱讀安裝說明,需佔用約1GB的硬碟空間。
3、一個C編譯器/開發環境,比如Linux下的GCC,OS X下的Xcode,Windows下的Visual Studio。
4、一個簡單的本地web伺服器,Linux/OS X下使用
python -m SimpleHTTPServer 9000
命令即可,Windows下可安裝IIS服務。
一、編寫C代碼
下面我們編寫一個非常簡單的C語言例子,它將會返回1-6的隨機數,在你所使用的工作目錄下,創建一個dice-roll.c文件。
#include<stdio.h>#include<stdlib.h>#include<time.h>#include<emscripten/emscripten.h>// 一旦WASM模塊被加載,main()中的代碼就會執行intmain(int argc, char ** argv){printf("WebAssembly module loaded\n");}// 返回1-6之間的一隨機數int EMSCRIPTEN_KEEPALIVE roll_dice(){srand ( time(NULL) );return rand() % 6 + 1;}
當我們將其編譯為wasm並且在瀏覽器中加載時,
main
函數會自動執行,其中的
printf
將會被翻譯成
console.log
。
我們想要
roll_dice
函數能夠在JavaScript中隨時調用,為此,我們需要在函數名前添加
EMSCRIPTEN_KEEPALIVE
標記以告訴Emscripten我們的意圖。
二、將C編譯為WebAssembly
現在我們已經有了C代碼,接下來需要將它編譯成wasm,不僅如此,我們還需要生成相應的JavaScript膠接代碼以便能夠真正運行起來。
這裡我們必須使用Emscripten編譯器,你會發現有大量的命令行參數和編譯方法可選,經過實踐,我們找到了下面這個最友好最實用的組合:
emcc dice-roll.c -s WASM=1 -O3 -o index.js
各個參數含義如下:
emcc——代表Emscripten編譯器;dice-roll.c——包含C代碼的文件;-s WASM=1——指定使用WebAssembly;-O3——代碼優化級別,3已經是很高的級別了;-o index.js——指定生成包含wasm模塊所需的全部膠接代碼的JS文件;
需要注意的是,儘管上面的emcc選項能夠很好地應對我們這個例子,但在更複雜的情況下,好需要使用不同的方法,可查看官方文檔了解更多內容:http://kripken.github.io/emscripten-site/docs/tools_reference/emcc.html#emccdoc。
三、在瀏覽器中加載WebAssembly代碼
現在我們將回到熟悉的web開發領域,在當前文件夾創建index.html文件,引入相關的js文件與CSS文件。
<!DOCTYPE html><head><metacharset="utf-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><title>WebAssembly 示例</title><metaname="viewport"content="width=device-width, initial-scale=1"><linkrel="stylesheet"href="CSS/styles.css"><linkrel="stylesheet"href="CSS/dice-1.0.min.css"></head><body><divclass="dice dice-6"></div><span>點擊以搖動篩子</span><!-- 引入JavaScript膠節文件 --><!-- 這將會加載WebAssembly模塊並運行其main函數 --><scriptsrc="index.js"></script></body></html>
至此,項目結構已經完整,如下:
style.css簡單設置一下頁面樣式:
body {padding: 40px;font: normal 16px sans-serif;display: flex;flex-direction: column;}.dice {display: block !important;font-size: 80px;margin: 0 auto 20px;cursor: pointer;}span {display: block;margin: 0 auto;color: #333;}
dice-1.0.min.js是來自Github(https://github.com/diafygi/dice-css)的一個微型CSS骰子樣式庫,包括了1-6的SVG矢量圖,可作為內聯圖標使用,用法與font-awesome和glyphicons相同。
由於跨源問題的存在,我們需要一個本地伺服器才能運行這個項目。在Linux/OS X系統中,可以在項目目錄下運行如下命令:
python -m SimpleHTTPServer 9000
然後到瀏覽器中,打開localhost:9000以查看這個小應用。按F12打開控制臺,即可看到我們在C代碼中使用printf輸出的問候語:
四、調用WebAssembly函數
最後一步是連接JavaScript與WebAssembly,由於膠接代碼的存在(index.js),這項任務變得非常簡單,它已經為我們處理好了所有的接線任務。
在瀏覽器中處理WebAssembly有一個非常強大的API可以使用,在此我們不會進行深入探討因為這已經超出了入門的範疇,我們只需要Module接口及其ccall方法這部分即可。該方法允許我們通過函數名從C代碼中調用一個函數,然後就向一般的JS函數一樣使用就行了。
var result = Module.ccall('funcName', // 函數名'number', // 返回類型['number'], // 參數類型[42]); // 參數調用此方法之後,result就將擁有對應C函數的所有功能,除函數名以外的所有參數都是可選的。我們也可以使用縮寫版:// 通過在函數名前添加下劃線來調用C函數var result = _funcName();
roll_dice
函數無需任何參數,在JavaScript代碼中調用十分簡單:
<script>// 當HTML dice元素被點擊時,其值將會被改變var dice = document.querySelector('.dice');dice.addEventListener('click', function(){// 調用C代碼中的roll_dice函數var result = _roll_dice();dice.className = "dice dice-" + result; });</script>
將上面這段代碼添加到index.html末尾,即
之前即可。
此時運行項目,即可看到結果:
總結
雖然現在WebAssembly還在發展的初期,但從公布的新標準來看,潛力巨大。在瀏覽器中運行低級語言的能力,將會帶來全新的應用程式與web體驗,而這,是僅僅通過JavaScript無法使用的。
誠然,使用WebAssembly在當前階段還十分繁瑣,文檔需要分為多個部分,相應的工具也不容易使用,並且還需要JavaScript膠接代碼才能使用wasm模塊。但隨著越來越多的人進入這個平臺,所有這些問題都將會被解決。
令附一些參考資料:
WebAssembly官網(www.webassembly.org/)WebAssembly on MDN(www.developer.mozilla.org/en-US/docs/WebAssembly)Awesome WASM(www.github.com/mbasso/awesome-wasm)Emscripten官網(www.kripken.github.io/emscripten-site/index.html)