我們之前說過,對於javascript來言,前端的世界千變萬化。前幾篇文章給大家說過用Emscripten來編譯C語言然後用到asm.js和WebAssembly,這種方法是可以始前端程式碼的執行速度提升很大,但是由於在實際的項目裡C語言缺乏很多高階特性,很多功能沒辦法實現,不利於開發大型的項目,而C++又太過於複雜,所以最後我選擇了用Rust。
一開始也糾結過要用Go還是Rust或Swift的,後來發現Go目前還不支援編譯到WebAssembly,Swift按理說應該可以支援的,因為都是用LLVM做的編譯器,不過沒有找到好的資料,好像說要自己編譯LLVM去支援https://stackoverflow.com/questions/46572144/compile-swift-to-webassembly 。另外對Rust的一些特性很是喜歡,聽說Rust很複雜,比較像Scala和Haskell,而偏偏我對Scala還算熟悉,也學過一下Haskell,所以決定試試看Rust。
https://github.com/ChristianMurphy/compile-to-web 這裡可以查看目前能編譯到WebAssembly的語言。
PS, 話說asm.js和Rust都是Mozilla搞的呢。
安裝Rust的管理工具rustup
rustup用於安裝管理Rust的相關工具,包括編譯器rustc、套件管理工具cargo等,支援安裝不同版本如stable, beta, nightly等以及在不同版本之間切換,類似於nvm。
curl https://sh.rustup.rs -sSf | sh
安裝Emscripten Rust編譯器
用rustup安裝最新體驗版(Nightly Version):
rustup toolchain add nightly rustup target add wasm32-unknown-emscripten --toolchain nightly
安裝cmake
#依平台自行選擇:
brew install cmake # MacOS, brew sudo port install cmake # MacOS, MacPorts sudo apt-get install cmake # Debian Linux
安裝Emscripten
參考前一篇,或直接執行下面指令:
wget https://s3.amazonaws.com/mozilla-games/emscripten/releases/emsdk-portable.tar.gz tar -xvf emsdk-portable.tar.gz cd emsdk-portable ./emsdk update ./emsdk install sdk-incoming-64bit
這一步花的時間比較久,據說要2個多小時,我是執行完命令就出去跟朋友吃飯了,所以具體時間不知道。
將下列路徑新增至PATH:
~/emsdk-portable ~/emsdk-portable/clang/fastcomp/build_incoming_64/bin ~/emsdk-portable/emscripten/incoming
終端執行emcc -v檢查是否安裝成功。
用Webpack執行Rust
新一個Rust/Javascript混合專案:
cargo new webasm --bin --vcs none cd webasm npm init rustup override set nightly
安裝Webpack, webpack-dev-server, rust-wasm-loader,
npm i -D webpack webpack-dev-server rust-wasm-loader
增加package.json腳本:
{ "name": "webasm", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "compile": "webpack --progress", "serve": "http-server", "start": "webpack-dev-server --content-base ./build" }, "author": "magicly", "license": "ISC", "devDependencies": { "http-server": "^0.10.0", "rust-wasm-loader": "^0.1.2", "webpack": "^3.6.0", "webpack-dev-server": "^2.8.2" } }
在build目錄下新檔案index.html:
<!DOCTYE html> <html> <head> <title>Hello WebAssembly</title> </head> <body> < div id="container"></div> <script src="/bundle.js"></script> </body> </html>
設定webpack.config.js:
module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: dirname + '/build', }, module: { rules: [ { test: /\.rs$/, use: { loader: 'rust-wasm-loader', options: { <span>// The path to the webpack output relative to the project root</span> path: '', release: true <span>// 没有的话性能巨差,差不多只有1/10</span> } } } ] }, <span>// The .wasm 'glue' code generated by Emscripten requires these node builtins,</span> <span>// but won't actually use them in a web environment. We tell Webpack to not resolve those</span> <span>// require statements since we know we won't need them.</span> externals: { 'fs': true, 'path': true, } }
新src/ main.rs文件,加入我們要從js中呼叫的函數:
fn main() { println!("Hello, world!"); } <span>// Functions that you wish to access from Javascript</span> <span>// must be marked as no_mangle</span> #[no_mangle] pub fn add(a: i32, b: i32) -> i32 { return a + b }
新建src/index.js,寫程式碼載入WebAssembly模組:
const wasm = require('./main.rs') wasm.initialize({ noExitRuntime: true }).then(module => { <span>// Create a Javascript wrapper around our Rust function</span> const add = module.cwrap('add', 'number', ['number', 'number']) console.log('Calling rust functions from javascript!') console.log(add(1, 2)) })
然後執行npm start,訪問http: //localhost:8080/就可以看到呼叫rust程式碼的效果了。並且也支援熱更新哦,直接修改rust程式碼,儲存,頁面就能看到最新效果。
測試了一下前一篇裡的程式碼,直接執行rust優化過的程式碼只需要300多ms,這個基本上跟C程式碼一樣,但用wasm運行,居然要2.7s左右,不知道是哪裡沒有配置好,還是說現在Rust編譯成wasm沒有優化好。 Rust支持WebAssembly應該還不是特別成熟,可以關注https://github.com/rust-lang/rust/issues/38804 跟進。
另外Rust有一個套件https://crates.io/crates/webplatform,可以用來操作DOM,不過我目前用不到(感覺沒啥用)
以上文章就是我對WEB的高效能運算的理解,希望能幫助到有需要的朋友,之前也有倆篇文章《asm.js & webassembly-WEB的高效能運算》,《asm.js & webassembly-WEB的高效能運算》,有需要的朋友可以去看一下。
推薦閱讀:
#以上是Rust -> asm.js & webassembly-WEB的高效能運算的詳細內容。更多資訊請關注PHP中文網其他相關文章!