日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

理解 Wasm 基礎概念,了解 Wasm 是如何被加載運行的?

來源: 責編: 時間:2023-12-06 09:19:05 230觀看
導讀大家好,我是前端西瓜哥,這次帶大家來簡單系統學習一下 wasm(WebAssembly)。示例源碼在這個 github 倉庫,可自行下載運行:https://github.com/F-star/wasm-demo。wasm 是如何被加載運行的?wasm 文件本身并不能像 JavaScript

uJ628資訊網——每日最新資訊28at.com

大家好,我是前端西瓜哥,這次帶大家來簡單系統學習一下 wasm(WebAssembly)。uJ628資訊網——每日最新資訊28at.com

示例源碼在這個 github 倉庫,可自行下載運行:uJ628資訊網——每日最新資訊28at.com

https://github.com/F-star/wasm-demo。uJ628資訊網——每日最新資訊28at.com

wasm 是如何被加載運行的?

wasm 文件本身并不能像 JavaScript 一樣,下載完成后就立即執行。uJ628資訊網——每日最新資訊28at.com

它更類似于 webgl 編譯著色器代碼,需要調用 JavaScript 提供的 API 去編譯執行。uJ628資訊網——每日最新資訊28at.com

wasm 被加載并執行的過程一般為:uJ628資訊網——每日最新資訊28at.com

  • 請求 wasm 文件。
  • 轉換為 ArrayBuffer 格式(也就是字節數組)。
  • 編譯并返回 Module 對象(異步的,可使用阻塞寫法)。
  • 基于 Module 創建一個 instance 實例(異步的,可使用阻塞寫法) 。instance 的 exports 對象下為 wasm 暴露出來的方法和屬性。創建 instance 有時需要提供一個額外的 importObject 對象,后文再細說。
  • 執行 JavaScript 代碼,調用 wasm 的方法,進行數據的交換。

代碼實例:uJ628資訊網——每日最新資訊28at.com

fetch('./add.wasm')  .then(rep => rep.arrayBuffer()) // 轉 ArrayBuffer  .then(bytes => WebAssembly.compile(bytes)) // 編譯為 module 對象  .then(module => WebAssembly.instantiate(module)) // 創建 instance 對象  .then(instance => {   // 拿到 wasm 文件暴露的 add 方法    const { add } = instance.exports;    console.log(add(12, 34));  });

上面是為了讓大家理解所有步驟,所以寫得很繁瑣。uJ628資訊網——每日最新資訊28at.com

我們有簡單寫法,用一個 API 把步驟 1、2、3、4 組合在一起:uJ628資訊網——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./add.wasm')).then(res => {  const { module, instance } = res;  const { add } = instance.exports;  console.log(add(12, 34));});

WebAssembly.instantiateStreaming 支持流式編譯,在 wasm 文件下載過程中就開始編譯了,并最后會一次性返回編譯和實例化產生的 module 和 instance 對象。uJ628資訊網——每日最新資訊28at.com

uJ628資訊網——每日最新資訊28at.com

wasm 目前現在無法像 ES Module 一樣,通過 import 的方式直接被引入(<script type="module">),將來會支持,且在提案中,但不會很快。uJ628資訊網——每日最新資訊28at.com

wat:wasm 文本格式

先寫一個 wasm。uJ628資訊網——每日最新資訊28at.com

原來我打算用 C 寫的,然后用 Emscripten 編譯,但我發現編譯出來的 wasm 有很多和 C 有關的冗余的代碼,且需要配合生成好的代碼量巨多的膠水 JavaScript 文件,有不少雜音。uJ628資訊網——每日最新資訊28at.com

為了更簡單些,我選擇寫 wat,然后轉為 wasm。uJ628資訊網——每日最新資訊28at.com

wat 指的是 wasm 的文本格式(WebAssembly text format)。wat 是一種低級語言,使用的是基于 S-表達式 的文本寫法,可以直接映射為 WASM 的二進制指令,你可以把它類比為匯編語言。uJ628資訊網——每日最新資訊28at.com

因為用 wat 手寫復雜邏輯并不可行,最后還是會用 C 或 Rust 這些高級語言去寫業務。uJ628資訊網——每日最新資訊28at.com

所以這里我不會講太多 wat 語法,目光更聚焦在 探究 wasm 是怎么和 js 通信的。uJ628資訊網——每日最新資訊28at.com

要實現 wat 轉 wasm,通常需要安裝 WABT(The WebAssembly Binary Toolkit)工具集,用 wat2wasm 命令行工具進行轉換。uJ628資訊網——每日最新資訊28at.com

如果覺得安裝麻煩,可以用 WABT 提供的一個在線轉換工具,貼 wat 文本上去點 download 按鈕即可得到 wasm。uJ628資訊網——每日最新資訊28at.com

uJ628資訊網——每日最新資訊28at.com

官方有提供 VSCode 插件,建議安裝,可以高亮 wat 語法。uJ628資訊網——每日最新資訊28at.com

另外可以選中文件右鍵菜單可進行 wat 和 wasm 互轉,但有點問題,一些正確的 wat 也會轉換失敗。uJ628資訊網——每日最新資訊28at.com

uJ628資訊網——每日最新資訊28at.com

每次修改完都要手動生成 wasm 可能有點繁瑣,可以考慮安裝 wabt 命令工具,并配合 nodemon 監聽 wat 文件,當文件被修改時自動編譯 wasm。uJ628資訊網——每日最新資訊28at.com

數字類型

(module  ;; 將兩個 i32 類型的參數相加返回  (func (export "add") (param i32 i32) (result i32)    local.get 0    local.get 1    i32.add  ))

這里定義了一個 add 方法,接收兩個 i32 類型的參數,相加并返回一個 i32 類型返回值。uJ628資訊網——每日最新資訊28at.com

wat 使用的棧式機器的方式執行的,將兩個參數依次壓入棧,然后調用相加運算,這個運算會取出棧頂的兩個數進行相加,然后把結果壓入棧。uJ628資訊網——每日最新資訊28at.com

最后函數會取棧頂的值作為返回值。uJ628資訊網——每日最新資訊28at.com

另外,目前 wasm 支持返回多個值了,JavaScript 那邊會得到一個數組。uJ628資訊網——每日最新資訊28at.com

;; 是行注釋,另外 (;注釋內容;) 是塊注釋。uJ628資訊網——每日最新資訊28at.com

wasm 的函數參數和返回值類型支持的數字類型有:i32、i64、f32、f64,分別代表 32 位和 64 位的整數和浮點數。(還有其他不常用的類型后面再講)uJ628資訊網——每日最新資訊28at.com

生成 add.wasm 文件,然后再寫一個 js 方法去加載調用 wasm 的方法:uJ628資訊網——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./add.wasm')).then(res => {  const { instance } = res;  const { add } = instance.exports;  console.log(add(100, 34));  console.log(add(100.233, 34)); // 浮點數被 add 轉成整數了  console.log(add(false, 34)); // true 被轉成 1,false 被轉成 0  // ...});

查看控制臺輸出:uJ628資訊網——每日最新資訊28at.com

uJ628資訊網——每日最新資訊28at.com

js 的數字只有一種類型:64 位浮點數,調用 wasm 函數會進行類型轉換,在上面的例子中,add 方法會將其轉為 32 位整數。uJ628資訊網——每日最新資訊28at.com

此外 js 的非數值類型也會轉為數字,通常是 0 或 1,字符串的話會嘗試轉為數字(類似調用 Number())。uJ628資訊網——每日最新資訊28at.com

wasm 函數的返回值也會做類型轉換為 js 的數字類型。如果返回的是 i64,在 JavaScript 會轉換為 BigInt。uJ628資訊網——每日最新資訊28at.com

下面是另一種可讀性更好的 wat 寫法。這里給函數參數聲明了名字,并給函數設置為變量,后面再導出(類似 js 的 export { add })。uJ628資訊網——每日最新資訊28at.com

(module  ;; 將兩個 i32 類型的參數相加返回  (func $add (param $a i32) (param $b i32) (result i32)    local.get $a    local.get $b    i32.add)  (export "add" (func $add)))

導入 JavaScript 方法

下面 wat 聲明了需要導入的 JavaScript 方法 a.b()。uJ628資訊網——每日最新資訊28at.com

(module  ;; wasm 會拿到 importObject 的 a.b 方法  (import "a" "b" (func $getNum (param i32)))  (func (export "getNum")    i32.const 114514    call $getNum ;; 這里把數字傳給了 importObject 的 a.b 方法  ))

導入的 js 方法需要聲明名稱和函數簽名。uJ628資訊網——每日最新資訊28at.com

實例化 module 時提供前面提到的 importObject,去指定這個方法。uJ628資訊網——每日最新資訊28at.com

const importObject = {  a: {    b: (num) => {      console.log('a.b', num) // 控制臺輸出:“a.b 114514”    }  }}WebAssembly.instantiateStreaming(fetch('./import.wasm'), importObject).then(res => {  const { getNum } = res.instance.exports;  getNum();});

調用 wasm 定義的 getNum 方法時,該方法會調用 js 聲明的 a.b() 方法,并傳入一個整數。uJ628資訊網——每日最新資訊28at.com

a 是模塊名,b 是這個模塊的一個屬性,模塊屬性除了可以是函數,也可以是其他的類型,比如線性內存 memory、表格 table。uJ628資訊網——每日最新資訊28at.com

我們寫 C 編譯成 wasm,其中的 printf 能夠在控制臺打印出來,就是調用了導入的 js 的膠水方法,把一些二進制數據轉換成 js 字符串,然后調用 console.log()  輸出。uJ628資訊網——每日最新資訊28at.com

全局變量

將從 importObject.js.global 傳過來的變量作為 wasm 的全局變量。uJ628資訊網——每日最新資訊28at.com

定義了兩個方法:uJ628資訊網——每日最新資訊28at.com

  • getGlobal:返回這個全局變量;
  • incGlobal:給全局變量 + 1。
(module  (global $g (import "js" "global") (mut i32))  (func (export "getGlobal") (result i32)    (global.get $g)  )  (func (export "incGlobal")    (global.set $g      (        i32.add        (global.get $g)        (i32.const 1)      )    )  ))

js 中用 new WebAssembly.Global() 創建 global 對象然后導入。uJ628資訊網——每日最新資訊28at.com

const importObject = {  js: {    // 一個初始值為 233 的 i32 變量    global: new WebAssembly.Global(      {        value: 'i32',        mutable: true,      },      233    ),  },};WebAssembly.instantiateStreaming(fetch('./global.wasm'), importObject).then(  (res) => {    const { instance } = res;    console.log(instance);    const { getGlobal, incGlobal } = res.instance.exports;    console.log('全局變量');    console.log(getGlobal()); // 輸出:233    incGlobal();    incGlobal();    console.log(getGlobal()); // 輸出:235  });

也可以在 js 中直接用 importObject.js.global.value 拿到全局變量的值。uJ628資訊網——每日最新資訊28at.com

也可以在 wasm 中定義 global 變量,global 變量可以定義多個。uJ628資訊網——每日最新資訊28at.com

(global $g2 (mut i32) (i32.const 99))

復雜變量類型

wasm 的函數無法接收和返回一些復雜的高級類型,比如字符串、對象,這時候就需要用到 線性內存(memory) 了。uJ628資訊網——每日最新資訊28at.com

線性內存需要用到 WebAssembly.Memory 對象,這個對象是 ArrayBuffer。uJ628資訊網——每日最新資訊28at.com

uJ628資訊網——每日最新資訊28at.com

js 和 wasm 共享這個 ArrayBuffer,作為傳輸媒介,然后雙方都在各自的作用域進行序列和反序列化。uJ628資訊網——每日最新資訊28at.com

這也是 wasm 讓人詬病的通信問題:uJ628資訊網——每日最新資訊28at.com

如果計算本身的 CPU 密集度不高,那瓶頸就落到數據序列化反序列化以及通信上了,別說提升性能了,降低性能都可能。uJ628資訊網——每日最新資訊28at.com

wat:uJ628資訊網——每日最新資訊28at.com

(module  (import "console" "log" (func $log (param i32 i32)))  ;; 傳入的 memory 大小為 1 頁  (import "js" "mem" (memory 1))  ;; 在 memory 的地址 0 處設置數據 "Hi"  (data (i32.const 0) "Hi")    (func (export "writeHi")    i32.const 0  ;; 字符串起始位置    i32.const 2  ;; 字符串長度    call $log  ))

js:uJ628資訊網——每日最新資訊28at.com

// memory 對象,大小為 1 頁(page),1 頁為 64 KBconst memory = new WebAssembly.Memory({ initial: 1 });// wasm 無法直接返回字符串,但可以修改線性內存// 然后再指定線性內存的區間讓 js 去截取需要的 ArrayBuffer// 最后 ArrayBuffer 轉 字符串function consoleLogString(offset, length) {  const bytes = new Uint8Array(memory.buffer, offset, length);  const string = new TextDecoder('utf-8').decode(bytes);  console.log(string);}const importObject = {  console: { log: consoleLogString },  js: { mem: memory },};WebAssembly.instantiateStreaming(fetch('./memory.wasm'), importObject).then(  (res) => {    res.instance.exports.writeHi();  });

也可以在 js 傳字符串給 wasm,但 js 這邊要做字符串轉 ArrayBuffer 的操作。uJ628資訊網——每日最新資訊28at.com

下面是拼接兩個字符串返回新字符串示例。uJ628資訊網——每日最新資訊28at.com

wat:uJ628資訊網——每日最新資訊28at.com

(module  (import "console" "log" (func $log (param i32 i32)))  (import "js" "mem" (memory 1))  ;; 函數接受兩個字符串并拼接它們  (func $concatStrings (param $offset1 i32) (param $length1 i32) (param $offset2 i32) (param $length2 i32) (result i32) (result i32)    ;; 這里的代碼是將兩個字符串拼接到內存中,并返回新字符串的偏移量和長度    ;; 注意:為了簡單起見,這里假設你有足夠的內存空間來拼接字符串    (local $newOffset i32)    ;; 假設新的偏移量是在第一個字符串的結束處    local.get $offset1    local.get $length1    i32.add    local.set $newOffset    ;; 將第二個字符串拷貝到新的偏移量處    local.get $newOffset    local.get $offset2    local.get $length2    memory.copy    ;; 返回新的偏移量和長度    local.get $offset1    local.get $length1    local.get $length2    i32.add  )  (func (export "concatAndLog") (param $offset1 i32) (param $length1 i32) (param $offset2 i32) (param $length2 i32)    ;; 調用上面的拼接函數    local.get $offset1    local.get $length1    local.get $offset2    local.get $length2    call $concatStrings    ;; 使用結果來調用$log    call $log  ))

js:uJ628資訊網——每日最新資訊28at.com

const memory = new WebAssembly.Memory({ initial: 1 });function consoleLogString(offset, length) {  // console.log(offset, length);  const bytes = new Uint8Array(memory.buffer, offset, length);  const string = new TextDecoder('utf-8').decode(bytes);  console.log(string); // 輸出 Hello, WebAssembly!}let currentOffset = 0; // 添加這個變量來跟蹤當前可用的內存偏移量function stringToMemory(str, mem) {  const encoder = new TextEncoder();  const bytes = encoder.encode(str);  new Uint8Array(mem.buffer, currentOffset, bytes.length).set(bytes);  const returnOffset = currentOffset;  currentOffset += bytes.length; // 更新偏移量  return { offset: returnOffset, length: bytes.length };}const importObject = {  console: { log: consoleLogString },  js: { mem: memory },};WebAssembly.instantiateStreaming(fetch('./concat.wasm'), importObject).then(  (res) => {    const str1 = 'Hello, ';    const str2 = 'WebAssembly!';    const mem1 = stringToMemory(str1, memory);    const mem2 = stringToMemory(str2, memory);    res.instance.exports.concatAndLog(      mem1.offset,      mem1.length,      mem2.offset,      mem2.length    );  });

其他類型也一樣的思路,只要支持轉換成 ArrayBuffer,然后轉換回來就好了。uJ628資訊網——每日最新資訊28at.com

一個 wasm 模塊只能定義一個線性內存 memory,這個是出于簡單的考量。uJ628資訊網——每日最新資訊28at.com

表格 table

table 是一個大小可變的引用數組,指向 wasm 的代碼地址。uJ628資訊網——每日最新資訊28at.com

前面的 wat 執行代碼時,會使用 run 指令接一個 靜態 的函數索引。但有時候函數索引需要是動態,一會指向函數 a,過一段時間又指向 b。uJ628資訊網——每日最新資訊28at.com

這時候我們就可以使用 table 去維護。uJ628資訊網——每日最新資訊28at.com

(table 2 funcref)

anyfunc 類型,代表可以是任何簽名的函數引用。uJ628資訊網——每日最新資訊28at.com

因為安全問題函數引用不能保存在線性內存(memory)中。因為線性內存保存地址沒意義,而存真正的函數數據源有可能被惡意修改,有安全問題。uJ628資訊網——每日最新資訊28at.com

所以整出了這么一個抽象的 table 數組,這個 table 無法被讀取真正的內容,只能更新一下數組的引用。uJ628資訊網——每日最新資訊28at.com

下面是一個示例,在 wat 創建了一個 table,然后讓 js 根據索引調用 table 中的動態引用的函數。uJ628資訊網——每日最新資訊28at.com

watuJ628資訊網——每日最新資訊28at.com

(module  ;; table 大小為 2,且為函數引用類型。  (table $t 2 funcref)  ;; table 從 0 偏移值填充聲明的兩個函數  ;; 0 指向 $f1,1 指向 $f2  (elem (i32.const 0) $f1 $f2)  ;; 函數聲明可以在任何位置  (func $f1 (result i32)    i32.const 22  )  (func $f2 (result i32)    i32.const 33  )  ;; 定義函數類型,一個返回 i32 的函數(類比 ts 的函數類型)  (type $return_i32 (func (result i32)))  ;; 暴露一個 callByIndex 方法給 js  ;; callByIndex(0) 表示調用 table 上索引為 0 的函數。  (func (export "callByIndex") (param $i i32) (result i32)    ;; (間接)調用 $i 索引值在 table 中指向的方法    call_indirect (type $return_i32)  ))

js:uJ628資訊網——每日最新資訊28at.com

WebAssembly.instantiateStreaming(fetch('./table.wasm')).then((res) => {  const { callByIndex } = res.instance.exports;  console.log(callByIndex(0)); // 22  console.log(callByIndex(1)); // 33});

也可以在 js 中更新 table,讓一些索引指向新的函數。uJ628資訊網——每日最新資訊28at.com

但需要注意,這個函數需要時 wasm 導出,而不是 js 函數。uJ628資訊網——每日最新資訊28at.com

下面是對應的示例。uJ628資訊網——每日最新資訊28at.com

wat:uJ628資訊網——每日最新資訊28at.com

(module   ;; 導入 table  (import "js" "table" (table 1 funcref))  (elem (i32.const 0) $f1)  (func $f1 (result i32)    i32.const 22  )  (type $return_i32 (func (result i32)))  (func (export "call") (result i32)    i32.const 0    call_indirect (type $return_i32)  )  (func (export "get666") (result i32)    i32.const 666  ))

js:uJ628資訊網——每日最新資訊28at.com

const table = new WebAssembly.Table({ initial: 1, element: 'anyfunc' });const importObject = {  js: { table },};WebAssembly.instantiateStreaming(  fetch('./outer-table.wasm'),  importObject).then((res) => {  const { call, get666 } = res.instance.exports;  console.log(call()); // 22  console.log(table.get(0)); // 獲取 wasm 函數  table.set(0, get666); // 更換 table[0] 的函數。  console.log(call()); // 666});

在 wat 中,anyfunc 是舊寫法,現在換成了 funcref,來表示函數引用。uJ628資訊網——每日最新資訊28at.com

不過 js 中創建 table,element 參數還得傳 "anyfunc"。uJ628資訊網——每日最新資訊28at.com

table 的這個特性可以實現類似 dll 的動態鏈接能力,可以在程序運行時才動態鏈接需要的代碼和數據。uJ628資訊網——每日最新資訊28at.com

引用類型

wasm 的函數現在支持傳 引用類型(externref)。uJ628資訊網——每日最新資訊28at.com

(func (export "callJSFunction") (param externref)  ...)

你可以傳任何 js 變量作為 externref 類型傳入 wasm 函數,但該變量在 wasm 不能被讀寫和執行,但可以把作為返回值,或是它作為參數傳給 import 進來的 js 函數。uJ628資訊網——每日最新資訊28at.com

wasm 只能對 externref 做中轉,傳入以及返回回去,無法做任何其他操作。uJ628資訊網——每日最新資訊28at.com

示例:uJ628資訊網——每日最新資訊28at.com

(module  (type $jsFunc (func (param externref)))  (func $invoke (import "js" "invokeFunction") (type $jsFunc))    (func (export "callJSFunction") (param externref)    local.get 0    call $invoke  ))
const importObject = {  js: {    invokeFunction: (fn) => {      fn();    },  },};WebAssembly.instantiateStreaming(fetch('./type.wasm'), importObject).then(  (res) => {    const { instance } = res;    const { callJSFunction } = instance.exports;    callJSFunction(() => {      console.log('被執行的是來自 js 函數');    });  });

矢量類型

v128,一個 128 比特的矢量類型。uJ628資訊網——每日最新資訊28at.com

用于 SIMD(Single Instruction, Multiple Data),它是一種計算機并行處理技術,允許一個單一的操作指令同時處理多個數據元素,使用用在大量數據執行相同操作的場景,比如矩陣運算。uJ628資訊網——每日最新資訊28at.com

v128 是其他數據的打包,打包一起好做并行運行,提高計算速度。uJ628資訊網——每日最新資訊28at.com

這些數據可能是:uJ628資訊網——每日最新資訊28at.com

  • 4 個 i32(或 f32)
  • 2 個 i64(或 f64)
  • 16 個 i8
  • 8 個 i16

然后它們會使用類似 i32x4 的指令進行批量操作:uJ628資訊網——每日最新資訊28at.com

i32x4.add (local.get $a) (local.get $b)

雖然沒有 i8 和 i16 這種類型,但它們本質是 ArrayBuffer(字節數組)的一種高層級,js 那邊可以用 ArrayBuffer 構造出 Int8Array 對象。uJ628資訊網——每日最新資訊28at.com

所以 wat 提供了對應的指令,比如 i8x16.add。uJ628資訊網——每日最新資訊28at.com

示例:uJ628資訊網——每日最新資訊28at.com

(module  (memory 1)  (export "memory" (memory 0))  (func (export "add_vectors")    (param $aOffset i32) (param $bOffset i32)    (local $a v128) (local $b v128)    (local.set $a (v128.load (local.get $aOffset)))    (local.set $b (v128.load (local.get $bOffset)))    (v128.store (i32.const 0) (i32x4.add (local.get $a) (local.get $b)))  ))
WebAssembly.instantiateStreaming(fetch('./v128.wasm')).then((res) => {  const { add_vectors, memory } = res.instance.exports;  // 首先在內存中分配兩個向量a和b  const a = new Int32Array(memory.buffer, 0, 4);  const b = new Int32Array(memory.buffer, 16, 4);  // 初始化向量a和b的值  a.set([1, 2, 3, 4]);  b.set([5, 6, 7, 8]);  console.log('Vector A:', a);  console.log('Vector B:', b);  // 調用add_vectors函數,傳入向量a和b在內存中的偏移量  add_vectors(0, 16);  // 讀取和打印結果  const result = new Int32Array(memory.buffer, 0, 4);  console.log('Result:', result); // [6, 8, 10, 12]});

uJ628資訊網——每日最新資訊28at.com

多線程

wasm 支持多線程。uJ628資訊網——每日最新資訊28at.com

我們可以使用多個 Web Worker 各自創建 wasm 實例,讓它們共享同一段內存 SharedArrayBuffer。uJ628資訊網——每日最新資訊28at.com

因為多線程特有的競態條件問題,我們需要用到 Atomics 對象,它提供了一些原子操作,防止沖突。uJ628資訊網——每日最新資訊28at.com

最后是 wait/notify 進行線程的掛起和喚醒。uJ628資訊網——每日最新資訊28at.com

這個用的不多,就簡單介紹一下就好了。uJ628資訊網——每日最新資訊28at.com

結尾

wasm 是 js 的一個強有力的補充,未來可期,在一些領域比如圖像處理、音視頻處理大有可為。uJ628資訊網——每日最新資訊28at.com

但也不得不承認 wasm 并不能很簡單地就能給應用提高性能的,因為安全原因,相比原生是有一定性能損失的。uJ628資訊網——每日最新資訊28at.com

如果沒做正確的設計甚至因為通信成本導致負優化,你需要考量性能的瓶頸在哪里,到底是代碼寫得爛呢還是 CPU 計算就是高。v8 的 JIT 過于優秀,導致 wasm 的光芒不夠耀眼。uJ628資訊網——每日最新資訊28at.com

另外,wasm 有不小的學習成本的。uJ628資訊網——每日最新資訊28at.com

但不可否認,wasm 是前端的一個大方向,還是有一定學習投入的必要。uJ628資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-38513-0.html理解 Wasm 基礎概念,了解 Wasm 是如何被加載運行的?

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: CSS_Flex 那些鮮為人知的內幕

下一篇: 優化技巧:如何加快Spring項目啟動速度

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 平定县| 石泉县| 长子县| 桐庐县| 阳泉市| 江西省| 九台市| 拉孜县| 达日县| 大厂| 江华| 乐昌市| 乌鲁木齐市| 台州市| 闽侯县| 阿巴嘎旗| 兰西县| 红桥区| 合作市| 东明县| 桐庐县| 罗江县| 岳西县| 巩义市| 鄂温| 新巴尔虎右旗| 太仆寺旗| 瓦房店市| 大悟县| 弥勒县| 镇赉县| 宁波市| 安义县| 东莞市| 榆中县| 申扎县| 隆化县| 长子县| 白银市| 墨脱县| 镇原县|