- WebAssembly實戰
- (加拿大)C.杰勒德·加倫特
- 8395字
- 2021-05-12 10:20:18
第 1 章 初識WebAssembly
本章內容
● WebAssembly是什么
● WebAssembly能解決什么問題
● WebAssembly的工作原理
● WebAssembly的安全性來自何處
● 哪些語言可用于創建WebAssembly模塊
提到Web開發,大多數開發者最關心的一件事就是性能——從網頁加載速度到整體的響應性。若干研究表明,如果網頁不能在3秒內完成加載,那么40%的訪問者就會離開。這個百分比會隨著網頁加載秒數的增加而增加。
網頁加載時間并不是唯一的問題。根據一篇谷歌論文所述,如果某個網頁的性能很差,那么會有79%的訪問者聲稱他們不太可能再次訪問該網站(參見Daniel An與Pat Meenan于2016年7月合著的文章“Why marketers should care about mobile page speed?”)。
隨著Web技術的發展,越來越多的應用程序轉移到Web上。這就向開發者提出了另一項挑戰,因為Web瀏覽器只支持一種編程語言:JavaScript。
從某種意義上說,在所有瀏覽器上只使用一種編程語言是好的——只需要編寫代碼一次,就可以確保它能在所有瀏覽器上運行。但仍需要在想要支持的每個瀏覽器上測試代碼,因為有時各個廠商的實現方式會略有不同。另外,有時一個瀏覽器廠商并不與其他廠商同時添加某項新功能。總體上說,只支持一種語言比支持四五種語言簡單一些。但瀏覽器只支持JavaScript的缺點是,我們想要移植到Web上的應用程序并不是用JavaScript編寫的,而是用C++這樣的語言編寫的。
JavaScript是一種很棒的編程語言,但現在我們要求它做的已經超出其本來的設計意圖(比如游戲所需要的密集型計算),并且還要求它能夠快速執行。
1.1 WebAssembly是什么
隨著瀏覽器開發商尋找提高JavaScript性能的方法,Mozilla(Firefox瀏覽器開發者)定義了一個名為asm.js的JavaScript子集。
1.1.1 WebAssembly的先驅:asm.js
asm.js具有以下優勢。
● 你并不直接編寫asm.js,而是用C或C++編寫邏輯,然后將其轉換為JavaScript。將代碼從一種語言轉換到另一種語言的過程稱為transpiling。
● 大計算量代碼可以更快地執行。當瀏覽器的JavaScript引擎看到名為asm pragma語句的特殊字符串("use asm";)時,其作用相當于一個標記,以此告訴瀏覽器它可以使用底層系統操作而不是更昂貴的JavaScript操作。
從第一次調用就可以獲得更快的代碼執行速度。包含的類型提示可以告知JavaScript一個變量會持有何種類型的數據。比如,可以用a|0來提示變量a將持有一個32位整型值。這種方法很有效,因為0的位OR運算不會改變原始值,所以這么做不會產生副作用。
這些類型提示作為一個承諾向JavaScript引擎表明,如果代碼將一個變量聲明為整型,那么它永遠不會被修改,比如不會改為字符串。因此,JavaScript引擎不需要監測代碼來確定這些類型,而是可以像代碼所聲明的那樣直接編譯它。
以下代碼片段展示了一個asm.js代碼示例。
function AsmModule() { "use asm"; ←---- 用于通知JavaScript后續代碼為asm.js的標記 return { add: function(a, b) { a = a | 0; ←---- 類型提示表明參數為32位整型 b = b | 0; return (a + b) | 0; ←---- 類型提示表明返回值為32位整型 } } }
雖然具有以上優點,但asm.js仍有一些缺點。
● 所有這些類型提示可能會使文件非常大。
● 因為asm.js文件是JavaScript文件,所以它仍然需要由JavaScript引擎讀入和解析。在像手機這樣的設備上,這會是個問題,因為所有處理過程延長了加載時間,而且會消耗電量。
● 為了添加新特性,瀏覽器廠商將不得不修改JavaScript語言本身,而這并不是我們所期望發生的。
● JavaScript是一種編程語言,并沒有設計用來作為編譯目標。
1.1.2 從asm.js到MVP
瀏覽器廠商關注改進asm.js的方法,他們想出了一個WebAssembly最小化可行產品(minimum viable product,MVP),其目標是保留asm.js的優點,同時解決其缺點。2017年,4個主流瀏覽器廠商(谷歌、微軟、Apple和Mozilla)都更新了自己的瀏覽器,以提供對此MVP(有時也稱為Wasm)的支持。
● WebAssembly是一種底層類匯編語言,能夠在所有當代桌面瀏覽器及很多移動瀏覽器上以接近本地的速度運行。
● WebAssembly文件設計得很緊湊,因此可以快速傳輸和下載。這些文件的設計方式也使得它們可以快速解析和初始化。
● WebAssembly被設計為編譯目標,因此用C++、Rust和其他語言編寫的代碼現在可以在Web上運行了。
后端開發者可以利用WebAssembly來提高代碼復用度或者無須重寫就將自己的代碼移植到Web中。Web開發者也可以從創建新庫、改進現有庫,以及提高自己代碼中大計算量部分的性能中獲益。盡管WebAssembly主要用于Web瀏覽器,但其設計也考慮到了可移植性,因此也可以在瀏覽器之外使用。
1.2 WebAssembly解決了哪些問題
WebAssembly MVP解決了asm.js的以下問題。
1.2.1 性能改進
WebAssembly致力于解決的最大問題之一是性能問題——從代碼的下載時間到代碼的執行速度。使用編程語言,而不是編寫計算機處理器理解的機器語言(1和0,或者本地代碼)時,你通常會編寫更接近于人類語言的某種東西。盡管使用從計算機細節中抽象出來的代碼更容易,但計算機處理器并不理解你的代碼,因此運行時需要將你編寫的內容轉換為機器碼。
JavaScript是一種解釋型編程語言,也就是說,它會在執行時讀入你編寫的代碼,并將這些指令即時翻譯為機器碼。使用解釋型語言時,不需要提前編譯代碼,這意味著它啟動的速度更快。但缺點是,解釋器必須在每次運行代碼時將指令轉換為機器碼。舉例來說,如果你的代碼在執行一個循環,那么每次執行該循環時,循環的每一行都要被解釋。因為解釋過程并不總有大量時間可用,所以并不總能進行優化。
其他編程語言(如C++)并不是解釋型的。使用這類語言時,需要利用稱為編譯器的特定程序預先將指令轉換為機器碼。使用編譯型編程語言時,需要一些時間將指令轉換為機器碼,然后才能運行它們,但其優點是有更多時間來優化代碼的執行;一旦指令編譯為機器碼,就不需要再次編譯。
隨著時間的發展,JavaScript已經從簡單連接多個組件的膠水語言(那時預計其生存期很短)發展為大量網站用于執行復雜處理的語言,它很容易涉及成百上千行代碼,而且,隨著單頁應用程序的興起,其代碼通常生存期很長?;ヂ摼W已經從只是展示文本和少量圖片的網站發展為具有強交互性的網站,甚至是稱為Web應用程序的站點,因為它們類似于桌面應用程序,只不過運行于Web瀏覽器中。
隨著開發者持續挑戰JavaScript的極限,一些引人注意的性能問題開始顯現出來。瀏覽器廠商決定要找到一個折中點,不僅可以獲得解釋器的優點,代碼被調用時能夠盡快啟動,而且擁有執行時能更快速運行的代碼。為了讓代碼更快,瀏覽器廠商引入了一個稱為JIT(just-in-time,即時)編譯的概念,JavaScript引擎在運行時監測代碼。如果某一部分代碼被使用的次數足夠多,那么引擎就會試圖將這一部分編譯為機器碼,這樣它就可以繞過JavaScript引擎,轉而使用底層系統方法,這要快得多。
JavaScript引擎需要監測代碼多次才能將其編譯為機器碼,因為JavaScript也是一種動態編程語言。在JavaScript中,一個變量可以持有任何類型的值。舉例來說,一個變量可能在最初持有一個整型值,但之后被賦予一個字符串。代碼運行若干次之后,瀏覽器才能了解應該預期什么(類型)。即使是在編譯后,也仍然需要監測這段代碼,因為某些條件可能會改變,此時需要拋棄這部分編譯后的代碼,重新開始整個處理過程。
1.2.2 比JavaScript更快的啟動速度
和asm.js一樣,WebAssembly不是設計用于手動編寫的,也不是供人類閱讀的。代碼被編譯為WebAssembly之后,字節碼會以二進制格式而不是文本格式表示,這可以減小文件大小,從而支持快速傳輸和下載。
這個二進制文件的設計方式使得模塊驗證可以在一輪內完成,其結構也支持并行編譯文件的不同部分。
通過實現JIT編譯,瀏覽器廠商在提高JavaScript性能方面獲得了巨大進步。但是JavaScript引擎只能在監測代碼若干次后才將其編譯為機器碼。另外,WebAssembly代碼是靜態類型的,即可以預知變量持有的值的類型。WebAssembly代碼可以從一開始就編譯為機器碼,無須先監測,因此第一次運行代碼就可以看到性能提升。
自MVP首次發布以來,瀏覽器廠商已經通過不同方式提升WebAssembly的性能。其中一種方式是引入了一種稱為流編譯的技術,在瀏覽器下載和接收文件時,該技術可以將WebAssembly代碼編譯為機器碼。流編譯支持WebAssembly模塊下載完畢即進行初始化,這樣會顯著加速模塊的啟動過程。
1.2.3 可以在瀏覽器中使用JavaScript之外的語言
目前為止,要想在Web上運行非JavaScript語言,需要將代碼轉換為JavaScript,但后者并未被設計為編譯目標。而WebAssembly從一開始就被設計為編譯目標,因此,如果開發者想要使用某種特定的語言進行Web開發,無須將代碼轉譯為JavaScript就可以實現。
因為WebAssembly沒有綁定到JavaScript語言,所以這項技術更容易改進,而無須擔心會影響JavaScript。這種獨立性促使WebAssembly具備大幅提升性能的能力。
對于WebAssembly MVP來說,C和C++是目標為WebAssembly的重點語言,但Rust也對此增加了支持,并且幾種其他語言也在試驗對它的支持。
1.2.4 代碼復用的機會
能夠用非JavaScript語言編寫代碼,并將其編譯為WebAssembly,對于代碼復用來說,這為開發者提供了更多靈活性。過去不得不用JavaScript重寫的東西現在可以直接在桌面或服務器上使用,并在瀏覽器中運行。
1.3 WebAssembly的工作原理
如圖1-1所示,使用JavaScript時,代碼被包含在網站中并在運行時解釋。因為JavaScript變量是動態的,所以觀察圖示中的函數add可以發現,當前處理的變量為何種類型并不是顯而易見的。變量a和b可能是整型、浮點型、字符串,甚至是它們的組合,比如一個變量是字符串,而另一個是浮點型。
圖1-1 JavaScript在執行過程中被編譯為機器碼
確定類型的唯一方法就是在代碼執行時進行監測,這也正是JavaScript引擎所做的。一旦獲得了這些變量的類型,引擎就可以將這段代碼轉換為機器碼。
WebAssembly不被解釋,而是由開發者提前編譯為WebAssembly二進制格式,如圖1-2所示。由于變量類型都是預知的,因此瀏覽器加載WebAssembly文件時,JavaScript引擎無須監測代碼。它可以簡單地將這段代碼的二進制格式編譯為機器碼。
圖1-2 C++轉換為WebAssembly,然后在瀏覽器中轉換為機器碼
1.3.1 編譯器工作原理概覽
1.2.1節簡單討論過這一點,開發者以更接近于人類語言的語言編寫代碼,但計算機處理器只能理解機器語言。因此,你編寫的代碼必須轉化為機器碼才能運行。前面沒有提到的是,每一類計算機處理器都有它自己的機器碼類型。
如果將每種編程語言都直接編譯為機器碼的各個版本,那么效率會很低。取而代之的是,如圖1-3所示,編譯器中稱為前端的部分會將你所編寫的代碼編譯為一種中間表示(intermediate representation,IR)。創建好IR代碼后,編譯器的后端部分會接收IR代碼,對其進行優化,然后將其轉換為所需要的機器碼。
圖1-3 編譯器的前端和后端
由于瀏覽器可以在若干不同的處理器(比如,從桌面計算機到智能手機和平板設備)上運行,因此為每個可能的處理器發布一個WebAssembly代碼的編譯后版本會非常繁復。圖1-4展示了替代方法,即取得IR代碼,并通過一個專門的編譯器來運行,這個編譯器將IR代碼轉換為一種專用字節碼并放入后綴為.wasm的文件中。
圖1-4 編譯器前端與WebAssembly后端合作
Wasm文件中的字節碼還不是機器碼,它只是支持WebAssembly的瀏覽器能夠理解的一組虛擬指令。如圖1-5所示,當加載到支持WebAssembly的瀏覽器中時,瀏覽器會驗證這個文件的合法性,然后這些字節碼會繼續編譯為瀏覽器所運行的設備上的機器碼。
圖1-5 Wasm文件加載到瀏覽器中,然后被編譯為機器碼
1.3.2 模塊的加載、編譯和實例化
本書撰寫時,下載Wasm文件到瀏覽器中并讓瀏覽器編譯它的過程是通過JavaScript函數調用完成的。我們期望未來會允許WebAssembly模塊與ES6模塊交互,這將會支持通過一個專門的HTML標簽(< script type="module">)來加載WebAssembly模塊,但目前還不支持這種形式。(ES是ECMAScript的簡稱,6是版本號。ECMAScript是JavaScript的官方名稱。)
在編譯這個模塊的二進制字節碼前,需要先驗證WebAssembly模塊的合法性,以確保這個模塊結構正確,從而確保代碼不會做任何不允許它做的事情,也不會訪問這個模塊不能訪問的內存。檢查也是在運行時進行的,以確保代碼位于它可以訪問的內存中。Wasm文件的組織結構使得驗證可以單輪完成,這樣可以確保驗證過程、編譯為機器碼,以及之后的實例化過程盡快完成。
瀏覽器將WebAssembly字節碼編譯為機器碼后,就可以將編譯后的模塊傳送給一個Web worker(第9章將深入討論Web worker,目前只需要了解Web worker是一種在JavaScript中創建線程的方式)或另一個瀏覽器窗口。甚至可以用這個編譯后的模塊創建這個模塊的更多實例。
編譯后,Wasm文件還需要進行實例化才能使用。實例化的過程包括接收需要的所有導入對象,初始化模塊元素,如果定義了啟動函數,那么還要調用啟動函數,最終向執行環境返回一個模塊實例。
WebAssembly與JavaScript
目前為止,允許在JavaScript虛擬機(virtual machine,VM)中運行的唯一語言是JavaScript。多年來,在試驗其他技術(如插件)時,它們需要創建自己的沙箱VM,這擴大了攻擊目標,也耗費了計算機資源。JavaScript VM首次開放自己,允許WebAssembly代碼也運行在同一個VM中。這帶來了幾點優勢,其中最大的優勢是,VM的安全性多年來已經被充分測試和強化過。如果創建一個新VM,那么它肯定會有一些安全性問題需要解決。
WebAssembly被設計為JavaScript的一個組件,而不是替代品。盡管我們很可能會看到有些開發者試圖只用WebAssembly來創建整個網站,但這可能不會是普遍情況。一些情況下,JavaScript仍然是更好的選擇。另一些情況下,網站可能需要包含WebAssembly來進行快速計算或提供底層支持。比如,有幾個瀏覽器將SIMD(single instruction, multiple data,單指令,多數據),即用單條指令處理多數據的能力,構建到了JavaScript之中,但瀏覽器廠商決定棄用其JavaScript實現,只通過WebAssembly模塊來提供SIMD支持。因此,如果網站需要SIMD支持,那么就需要包含一個WebAssembly模塊來與之通信。
為Web瀏覽器編程時,基本上有兩個主要組件:JavaScript VM(WebAssembly模塊運行于其中)以及Web API(比如DOM、WebGL、Web worker等)。作為MVP,WebAssembly是缺乏某些東西的。WebAssembly模塊可以與JavaScript通信,但是還不能與任何Web API直接交流?,F在正在開發一項后MVP特性,該特性將允許WebAssembly直接訪問Web API。目前,模塊可以調用JavaScript與Web API交流,讓JavaScript代表模塊執行所需要的動作。
1.4 WebAssembly模塊的結構
目前WebAssembly只能使用4種值類型:
● 32位整型
● 64位整型
● 32位浮點型
● 64位浮點型
布爾值用32位整型表示,0為false,非0值為true。所有其他值類型(如字符串)需要在模塊的線性內存空間中表示。
WebAssembly程序的主要單元稱為模塊,這個術語既用來表示代碼的二進制版本,也表示瀏覽器中的編譯后版本。你并不需要手動創建WebAssembly模塊,但是對模塊結構及其底層工作原理有一定了解是有所幫助的,因為在模塊的初始化過程和整個生存期內,你都要與它的某些方面交互。
圖1-6是一個WebAssembly文件結構的基本表示。第2章將進一步介紹模塊的結構,目前先進行簡單的概述。
圖1-6 WebAssembly文件結構的基本表示
Wasm文件以一個名為前導(preamble)的段開始。
1.4.1 前導
前導中包含一個幻數(magic number,0x00 0x61 0x73 0x6D,即\0asm),用于區分WebAssembly模塊與ES6模塊。這個幻數之后是版本號(0x01 0x00 0x00 0x00,即1),以指明創建本文件時使用的WebAssembly二進制格式的版本。
目前這個二進制格式只有一個版本。WebAssembly的目標之一是在引入新特性的同時保持一切向后兼容,避免不得不增加版本號的情況。如果出現了必須破壞現有內容來實現的特性,那么就得遞增版本號。
前導之后,模塊可以有若干個段,但每一段都是可選的,因此嚴格來說可以存在沒有任何段的空模塊。第3章會介紹空模塊的一個用例,它可以在判斷某個Web瀏覽器是否支持WebAssembly時發揮作用。
可用的段分為兩類:已知段和自定義段。
1.4.2 已知段
已知段只能被包含一次,并且要按照特定順序出現。每個已知段都有良好的定義、專門的用途,進行模塊初始化時會檢驗其有效性。第2章會深入介紹已知段。
1.4.3 自定義段
自定義段為用戶提供了在模塊內包含數據的一種方法,應用于已知段不適用的情況。自定義段可以出現在模塊的任意位置(已知段的前、后或之間)任意多次,多個自定義段甚至可以復用同一個名字。
與已知段不同,如果某個自定義段的布局不正確,那么將不會觸發驗證錯誤。框架可以惰性加載自定義段,也就是說,它們包含的數據可能直到模塊初始化到某個階段才有效。
WebAssembly MVP有一個名為“name”的自定義段。這個段背后的思路是,WebAssembly模塊可以有一個調試版本,在調試時,這個段會持有文本形式的函數和變量名。與其他自定義段不同,這個段應該只出現一次,并且只出現在Data段之后。
1.5 WebAssembly文本格式
WebAssembly的設計并沒有忘記Web的開放性,其二進制格式不是設計供人類讀寫的,但并不能因此就認為WebAssembly模塊是開發者試圖隱藏代碼的一種方式。實際上,恰好相反。開發者為WebAssembly定義了一種使用s-表達式的文本格式,以對應二進制格式。
信息 符號表達式(或s-表達式)是為Lisp編程語言發明的。一個s-表達式可以是一個原子或一個s-表達式的有序對,后者支持s-表達式的嵌套。原子是一個非列表的符號,比如foo或23。列表用括號表示,可以是空的,也可以持有原子或其他列表;成員之間用空格分隔,比如()、(foo),以及(foo (bar 132))。
舉例來說,這個文本格式允許瀏覽器中的代碼支持View Source,也可以用于調試。甚至可以手動編寫s-表達式,然后用專門的編譯器將代碼編譯為WebAssembly二進制格式。
因為選擇View Source以及用于調試目的時瀏覽器會使用WebAssembly文本格式,所以對文本格式有基本了解是有用的。比如,既然模塊的所有段都是可選的,那么可以使用下列s-表達式定義一個空模塊。
(module)
如果要將s-表達式(module)編譯為WebAssembly二進制格式,并觀察得到的二進制值,那么這個文件會只包含前導字節:0061 736d(幻數)和0100 0000(版本號)。
預告 第11章將只用文本格式創建一個WebAssembly模塊,這樣一來,查看其內容時(比如需要在瀏覽器中調試模塊時),你可以更好地理解。
1.6 WebAssembly如何獲得安全性
WebAssembly的安全性來源之一是,它是第一個共享JavaScript VM的語言,而JavaScript VM在運行時是沙箱化的,同時也經歷了多年的檢驗和安全測試,這確保了其安全性。WebAssembly模塊的可訪問范圍不超過JavaScript的訪問范圍,同時也會遵守相同的安全性規則,包括同源策略(same-origin policy)這樣的增強規則。
與桌面應用程序不同,WebAssembly模塊對設備內存沒有直接訪問權限,而是運行時環境在初始化過程中向模塊傳遞一個ArrayBuffer。模塊將這個ArrayBuffer當作線性內存來使用,WebAssembly框架執行檢查以確保代碼不會對這個數組進行越界操作。
對于像函數指針這樣存儲在Table段中的項目,WebAssembly模塊也不能直接訪問。代碼會用索引值向WebAssembly框架提出訪問某個項目的請求。然后框架訪問內存,并代表代碼執行這個項目。
在C++中,執行棧與線性內存一起位于內存中,雖然C++代碼不應該修改執行棧,但是它可以使用指針實現修改。WebAssembly的執行棧與線性內存是分離的,代碼無法訪問。
更多信息 要想了解關于WebAssembly安全性模型的更多信息,可以訪問WebAssembly官方網站。
1.7 哪些語言可用來創建WebAssembly模塊
為了創建這個MVP,WebAssembly的最初關注點在C和C++語言上,但后來Rust和AssemblyScript這樣的語言也增加了支持。也可以使用WebAssembly文本格式通過s-表達式編寫代碼,然后用專門的編譯器將其編譯為WebAssembly。
現在,WebAssembly的MVP還沒有垃圾回收(garbage collection,GC),這限制了某些語言的使用。GC作為一種后MVP功能正在開發中,但在其實現之前,有幾種語言正在試驗WebAssembly支持,方式是將自己的VM編譯到WebAssembly,或者在某些情況下將自己的垃圾回收器包含進去。
以下語言正在試驗或已經擁有WebAssembly支持。
● C和C++。
● Rust正致力于成為WebAssembly的首選編程語言。
● AssemblyScript是一種新編譯器,它接受TypeScript并將其轉換為WebAssembly??紤]到TypeScript是帶類型的并且已經可以轉譯到JavaScript,轉換它是有意義的。
● TeaVM是一個將Java轉譯到JavaScript的工具,現在也可以生成WebAssembly了。
● Go 1.11為WebAssembly增加了一個試驗性項目,其編譯后的WebAssembly模塊包含一個垃圾回收器。
● Pyodide是Python的一個項目,其中包含了Python科學棧的核心包:Numpy、Pandas和matplotlib。
● Blazor是微軟的實驗性項目,用于將C#引入WebAssembly。
更多信息 GitHub網站上維護了一個語言列表(Awesome WebAssembly Language),其中的語言可以編譯到WebAssembly,或者將其VM放入WebAssembly。這個列表也指明了這些語言對WebAssembly的支持程度。
本書將使用C和C++語言來學習WebAssembly。
1.8 我的模塊可以用在何處
2017年,所有的現代瀏覽器廠商都發布了支持WebAssembly MVP的瀏覽器,其中包括Chrome、Edge、Firefox、Opera和Safari。一些移動Web瀏覽器也支持WebAssembly,其中包括Chrome、Android Firefox和Safari。
正如本章開頭所述,WebAssembly在設計時就考慮了可移植性,因此它可以用于多個場合,而不限于瀏覽器。一個名為WASI(WebAssembly Standard Interface,WebAssembly標準接口)的新標準正在開發之中,它確保了WebAssembly模塊可以在所有受支持系統上保持一致性。以下文章對WASI進行了很好的概述:Lin Clark撰寫的“Standardizing WebAssemblySI: A system interface to run WebAssembly outside the Web”(2019年3月27日)。
更多信息 如果想深入學習WASI,可以在GitHub網站上找到相關鏈接和文章的索引列表(Awesome WASI)。
從版本8開始,Node.js就是支持WebAssembly模塊的一個非瀏覽器環境。Node.js是一個JavaScript運行時,由Chrome的V8 JavaScript引擎構建,支持在服務器端使用JavaScript代碼。很多開發者將WebAssembly看作在瀏覽器(而不是JavaScript)中使用他們熟悉的代碼的機會,與之類似,Node.js讓喜歡JavaScript的開發者也可以在服務器端使用它。為了展示WebAssembly在瀏覽器之外的使用,第10章將介紹如何在Node.js中使用WebAssembly模塊。
WebAssembly并不是JavaScript的替代品,而是它的一個補充。有些情況下,使用WebAssembly模塊是更好的選擇,有些情況下則更應該使用JavaScript。與JavaScript在同一個VM中運行可以讓兩種技術利用彼此。
WebAssembly為熟練使用非JavaScript的開發者開啟了一扇門,以幫助他們在Web中使用自己的代碼。它也讓不了解如何編寫像C或C++ 這樣的代碼的Web開發者可以訪問更新、更快的庫,以及那些擁有當前JavaScript庫不支持的功能的庫。某些情況下,WebAssembly可以被一些庫用于加速庫的某些部分的執行速度。除了擁有更快的代碼之外,這個庫的工作方式與通常無異。
關于WebAssembly最令人激動的一點是,在所有主流桌面瀏覽器、幾個主要移動瀏覽器,甚至瀏覽器之外的Node.js之中,它都是可用的。
1.9 小結
如本章所述,WebAssembly實現了若干性能改進,以及對語言選擇和代碼復用方面的改進。WebAssembly帶來的幾個關鍵改進如下。
● 傳輸和下載更快,因為二進制編碼使得文件更小。
● 鑒于Wasm文件的結構,它們可以被快速解析和驗證,同時文件的各個部分可以并行編譯。
● 通過流編譯技術,可以在下載WebAssembly模塊的同時編譯它,這樣一來,下載完畢時就可以實例化這個模塊,從而大大加速加載過程。
● 對于計算這樣的功能來說,代碼可以更快地執行,因為使用了機器級調用,而不是更昂貴的JavaScript引擎調用。
● 編譯前不需要檢測代碼以確定其行為方式。結果是代碼每次運行的速度都相同。
● 與JavaScript分離,可以更快地改進WebAssembly,因為這不會影響JavaScript語言。
● 可以在瀏覽器中使用非JavaScript語言編寫的代碼。
● 通過改變WebAssembly的框架結構,實現其在瀏覽器內外部的使用,從而增加代碼復用的機會。
- Oracle 11g從入門到精通(第2版) (軟件開發視頻大講堂)
- Learning C++ Functional Programming
- HBase從入門到實戰
- The React Workshop
- 實戰低代碼
- Internet of Things with Intel Galileo
- Visual C
- Visual Basic程序設計實驗指導(第4版)
- Hands-On Swift 5 Microservices Development
- Learning jQuery(Fourth Edition)
- 現代C++編程實戰:132個核心技巧示例(原書第2版)
- C陷阱與缺陷
- Struts 2.x權威指南
- 跟戴銘學iOS編程:理順核心知識點
- Hands-On Robotics Programming with C++