WebAssembly簡介

了解為什麼WebAssembly是未來Web平台的重要組成部分

Web組裝如今是一個非常酷的話題。

WebAssembly是Web的一種新的低級二進制格式。它不是您要編寫的編程語言,而是將其他高級語言(目前為C,Rust和C ++)編譯為WebAssembly,以便有機會在瀏覽器中運行。

它被設計為快速,內存安全和開放的。

您永遠不會在WebAssembly(也稱為WASM)中編寫代碼,而WebAssembly是將其他語言編譯成的低級格式。

在90年代引入JavaScript之後,這是Web瀏覽器可以理解的第二種語言。

WebAssembly是由W3C WebAssembly工作組。如今,所有現代瀏覽器(Chrome,Firefox,Safari,Edge,移動瀏覽器)和Node.js都支持它。

我是說Node.js嗎?是的,因為WebAssembly誕生於瀏覽器中,但是Node從版本8開始已經支持它,並且您可以使用JavaScript以外的任何其他語言來構建Node.js應用程序的一部分。

由於WebAssembly,不喜歡JavaScript或更喜歡用其他語言編寫的人現在可以選擇使用不同於JavaScript的語言為Web編寫應用程序的一部分。

請注意:WebAssembly不能替代JavaScript,但這是將用其他語言編寫的程序移植到瀏覽器,以增強應用程序部分的一種方法,這些部分可以用這些語言更好地創建或預先存在。

JavaScript和WebAssembly代碼可以互操作,以在Web上提供出色的用戶體驗。

這是Web上的雙贏,因為我們可以利用JavaScript的靈活性和易用性,並通過WebAssembly的功能和性能對其進行補充。

安全

WebAssembly代碼在沙盒環境中運行,具有與JavaScript相同的安全策略,並且瀏覽器將確保同源策略和權限策略。

如果您對該主題感興趣,我建議您閱讀WebAssembly中的內存webassembly.org的安全性文檔

表現

WebAssembly專為提高速度而設計。它的主要目標是真正,非常快。這是一種編譯語言,這意味著程序將在執行之前轉換為二進製文件。

它可以達到可以與本地編譯語言(如C)緊密匹配的性能。

與JavaScript是動態的解釋型編程語言相比,速度是無法比較的。 WebAssembly總是會擊敗JavaScript性能,因為執行JavaScript時,瀏覽器必須解釋指令並進行動態優化。

今天誰在使用WebAssembly?

WebAssembly可以使用了嗎?是的!許多公司已經在使用它來改善他們在Web上的產品。

您可能已經使用的一個很好的例子是菲格瑪,這是一個設計應用程序,我還可以使用它來創建我在日常工作中使用的一些圖形。該應用程序在瀏覽器中運行,並且速度非常快。

該應用程序是使用React構建的,但該應用程序的主要部分(圖形編輯器)是編譯為WebAssembly的C ++應用程序,並使用WebGL在Canvas中呈現。

在2018年初,AutoCAD發布了其流行的設計產品,該產品在Web App內運行,使用WebAssembly呈現其複雜的編輯器,該編輯器是使用C ++構建的(並從桌面客戶端代碼庫中移植)

對於那些需要非常高性能的產品而言,Web不再是一種限制技術。

如何使用WebAssembly?

可以使用以下命令將C和C ++應用程序移植到WebAssembly腳本,可以將您的代碼編譯成兩個文件的工具鏈:

  • 一種.wasm文件
  • 一種.js文件

在哪裡.wasm文件包含實際的WASM代碼,並且.js文件包含將允許JavaScript代碼運行WASM的粘合劑。

Emscripten將為您做很多工作,例如將OpenGL調用轉換為WebGL,將為DOM API和其他瀏覽器和設備API提供綁定,將提供可在瀏覽器內部使用的文件系統實用程序,等等。默認情況下,這些東西不能直接在WebAssembly中訪問,所以這是一個很大的幫助。

Rust代碼是不同的,因為它可以直接編譯為WebAssembly作為其輸出目標,並且有一個https://developer.mozilla.org/zh-CN/docs/WebAssembly/Rust_to_wasm

未來WebAssembly會有什麼發展?進展如何?

WebAssembly現在是1.0版。目前,它僅正式支持3種語言(C,Rust,C ++),但還會有更多語言支持。 Go,Java和C#當前無法(正式)編譯為WebAssembly,因為尚不支持垃圾回收。

當前使用WebAssembly調用瀏覽器API時,您當前首先需要與JavaScript進行交互。正在使WebAssembly在瀏覽器中成為更高級的公民,並使它能夠直接調用DOM,Web Workers或其他瀏覽器API的工作正在進行中。

此外,正在進行一些工作,以使JavaScript代碼能夠通過以下方式加載WebAssembly模塊:ES模塊規格。

安裝Emscripten

通過克隆來安裝EmscriptenemsdkGitHub倉庫:

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

然後

dev cd emsdk

現在,請確保您已安裝最新版本的Python。我有2.7.10,這導致了TLS錯誤。

我必須從下載新的(2.7.15)https://www.python.org/getit/安裝它,然後運行Install Certificates.command安裝附帶的程序。

然後

./emsdk install latest

讓它下載並安裝軟件包,然後運行

./emsdk activate latest

並通過運行以下命令將路徑添加到您的shell:

source ./emsdk_env.sh

將C程序編譯為WebAssembly

我將創建一個簡單的C程序,我希望它在瀏覽器中執行。

這是一個非常標準的“ Hello World”程序:

#include <stdio.h>

int main(int argc, char ** argv) {
  printf("Hello World\n");
}

您可以使用以下命令進行編譯:

gcc -o test test.c

並運行./test會在控制台上打印“ Hello World”。

讓我們使用Emscripten編譯該程序以在瀏覽器中運行它:

emcc test.c -s WASM=1 -o test.html

Emscripten給了我們一個HTML頁面,該頁面已經包裝了已編譯的WebAssembly程序,可以運行了。但是,您需要從Web服務器而不是本地文件系統中打開它,因此請啟動本地Web服務器,例如http-server全局npm軟件包(使用安裝npm install -g http-server(如果尚未安裝)。這裡是:

The program running in the browser

如您所見,該程序已運行並在控制台中打印了“ Hello World”。

這是運行編譯為WebAssembly的程序的一種方法。另一個選擇是使程序公開要從JavaScript調用的函數。

從JavaScript調用WebAssembly函數

讓我們調整之前定義的Hello World。

包括emscripten標頭:

#include <emscripten/emscripten.h>

並定義一個hello功能:

int EMSCRIPTEN_KEEPALIVE hello(int argc, char ** argv) {
  printf("Hello!\n");
  return 8;
}

EMSCRIPTEN_KEEPALIVE如果不從調用,則需要保留該功能以防止該功能被自動剝離main()或其他在啟動時執行的代碼(因為編譯器會優化生成的編譯代碼並刪除未使用的函數-但我們將通過JS動態調用此代碼,並且編譯器現在知道這一點)。

This little function prints Hello! and returns the number 8.

現在,如果我們再次使用emcc

emcc test.c -s WASM=1 -o test.html -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap']"

這次我們添加了一個EXTRA_EXPORTED_RUNTIME_METHODS標誌告訴編譯器離開ccallcwrapModule對像上的函數,我們將在JavaScript中使用這些函數。

現在,我們可以再次啟動Web服務器,並在頁面打開後調用Module.ccall('hello', 'number', null, null)在控制台中,它將顯示“ Hello!”並返回8:

Calling from JS

這四個參數Module.ccall需要的是C函數名稱,返回類型,參數的類型(數組)和參數(也是數組)。

例如,如果我們的函數接受2個字符串作為參數,則我們將這樣調用它:

Module.ccall('hello', 'number', ['string', 'string'], ['hello', 'world'])

我們可以使用的類型是nullstringnumberarrayboolean

我們還可以為hello通過使用功能Module.cwrap函數,以便我們可以使用JS對應對像多次調用該函數:

const hello = Module.cwrap('hello', number, null, null)

Using cwrap

這是官方文檔ccallcwrap

免費下載我的JavaScript初學者手冊


更多js教程: