WebAssembly,簡稱 WASM,是一種定義低階程式語言的標準,它適合 (A) 作為許多其他語言交叉編譯的目標,以及 (B) 透過瀏覽器中的虛擬機器執行。基於 JavaScript 腳本化的設計理念,它提供一種將 C 語言程式碼(以及其他語言)編譯成 WASM 並透過 JavaScript 進行腳本化的方式,儘管 JavaScript 和 C 語言之間存在巨大差異,但摩擦相對較小。
人們從2012 年就開始為網路建構 sqlite3,但這個子專案是第一個「官方」與 SQLite 專案相關的成果,其目標是讓 WASM 版本的函式庫成為 SQLite 支援交付品系列中的一級成員。
本專案的具體目標
本專案的具體目標包括……
除了非目標中提到的部分外,盡可能提供一個功能完備的 sqlite3 C API 包裝器,只要 WASM 功能與 C 語言相容。實際上,提供至少以下 API……
- 綁定一個低階 sqlite3 API,使其在使用方面盡可能接近原生 API。
- 一個更高階的物件導向 API,更類似於 sql.js 和 node.js 風格的實作。這個 API 直接與低階 API 對話。這個 API 必須與低階 API 在同一個執行緒中使用。
- 一個基於 Worker 的 API,它透過 Worker 訊息與先前的 API 進行通訊。這個 API 旨在主執行緒中使用,低階 API 安裝在 Worker 執行緒中,並透過 Worker 訊息與它們通訊。由於 Worker 是非同步的,並且只有一個訊息通道,因此需要一些技巧才能將非同步工作結果回傳給用戶端(因為我們不能簡單地在主執行緒和 Worker 執行緒之間傳遞回呼函式)。
- 一個基於 Promise 的 Worker API 變體(上述 #3),它完全向使用者隱藏了跨執行緒通訊的細節。
盡可能使用可用的 JS API 支援用戶端持久儲存。截至撰寫本文時,這包括Origin-Private FileSystem (OPFS) 以及透過
window.localStorage
和window.sessionStorage
後端的(非常有限的)儲存。
非目標
我們明確不打算實現的目標
由於 WASM 是一項以網路為中心的技術,而 UTF-8 是該領域的編碼之王,因此目前沒有支援 UTF16 相關 sqlite3 API 的計畫。它們會增加綁定的複雜性,而沒有明顯的好處。
雖然對瀏覽器外 WASM 執行環境的支援很普遍,但本專案目前僅專注於瀏覽器目標。雖然與網路相關的實作細節優先,且 API 的 JavaScript 元件專注於瀏覽器用戶端,但低階 WASM 模組「應該」可以在非網路 WASM 環境中運作,前提是該環境可以提供 WASM 檔案所需的「匯入」。
支援舊版或利基市場平台。WASM 是為現代網路建構的,需要現代平台。同樣,已棄用的 sqlite3 函式庫選項也不包含在 WASM 介面中。
致謝
幾個專案在過程中給予我們相當大的幫助。我們非常感謝(按照我們調查它們的順序)……
Emscripten
截至撰寫本文時,Emscripten WASM 工具鏈是唯一功能齊全的 WASM 工具鏈。雖然存在其他工具鏈,但 Emscripten 提供了其他工具鏈沒有的幾個「殺手級功能」,最值得注意的是 POSIX 檔案 I/O API 的透明模擬,這使得 sqlite3 可以在 WASM 版本中按原樣運作,而無需任何更改或調整。
此外,Emscripten 的開發人員在開發基於 OPFS 的功能時,直接提供了寶貴的支持。
sql.js
https://github.com/sql-js/sql.js
Alon Zakai 的 sql.js
是這段程式碼開發過程中重要的墊腳石,它展示了如何處理一些與 WASM 相關的技巧(例如處理指向指標的指標,以及新增 C 語言綁定回呼函式的 JS 實作)。 然而,這些 API 的形狀與 sql.js
相當不同。
據我們所知,sql.js
是第一個公開發布的網頁版 sqlite3。
absurd-sql
https://github.com/jlongster/absurd-sql
James Long 名副其實的 absurd-sql
透過將資料庫儲存在 IndexedDB 儲存空間中,展示了瀏覽器端的 sqlite3 持久化。我們也嘗試過這種方法,但它並不適合我們。即便如此,這還是一個有趣的實驗。
wa-sqlite
https://github.com/rhashimoto/wa-sqlite
Roy Hashimoto 的 wa-sqlite
是第一個公開發布 sqlite3 之 OPFS 儲存選項的專案。它還提供了如何使用其他方面幾乎沒有說明文件的OPFS API 的完整示範。