Module 物件

Module 是一個全域 JavaScript 物件,具有 Emscripten 產生的程式碼在其執行期間各個點呼叫的屬性。

開發人員可以提供 Module 的實作來控制程式碼的執行。例如,為了定義如何顯示來自 Emscripten 的通知訊息,開發人員會實作 Module.print 屬性。

當 Emscripten 應用程式啟動時,它會查看 Module 物件上的值並套用它們。請注意,在啟動變更這些值通常不會生效;在啟用 ASSERTIONS 的建置中,您會在該情況下收到錯誤。

注意

Module 也用於以安全的方式提供對 Emscripten API 函式的存取(例如 ccall())。任何匯出的函式或執行階段方法(針對編譯函式使用 EXPORTED_FUNCTIONS,或針對 ccall 等執行階段方法使用 EXPORTED_RUNTIME_METHODS)都可以在 Module 物件上存取,而不會因為縮小化而變更名稱,且最佳化器會確保保留函式存在(且不會因為未使用而移除)。請參閱相關常見問題項目

建立 Module 物件

使用 emcc 的 pre-js 選項來新增 JavaScript 程式碼,該程式碼使用您需要的行為定義(或延伸)Module 物件。

當只產生 JavaScript(而不是 HTML)時,預設不會建立 Module 物件,且行為完全由開發人員定義。例如,建立具有下列程式碼的 Module 物件會導致程式的所有通知都呼叫 alert()

var Module = {
  'print': function(text) { alert('stdout: ' + text) },
  'printErr': function(text) { alert('stderr: ' + text) }
};

重要

如果您在程式碼上執行 Closure Compiler(這是選用的,且可以使用 --closure 1 來完成),您需要在 Module 的屬性周圍加上引號,如上述範例所示。此外,您需要將 closure 與 Module 的宣告一起執行編譯程式碼 — 這會針對 --pre-js 檔案自動完成。

當產生 HTML 時,Emscripten 會建立具有預設方法的 Module 物件(請參閱 src/shell.html)。在此情況下,您應該再次使用 --pre-js,但這次您會將屬性新增至現有的 Module 物件,例如

Module['print'] = function(text) { alert('stdout: ' + text) };

請注意,一旦主要 JavaScript 檔案收到 Module 物件,它將在該時間尋找 Module['print'] 等等,並相應地使用它們。稍後變更它們的值可能不會被注意到。

編譯設定

INCOMING_MODULE_JS_API 編譯器設定控制在發出的 JS 中支援哪些 Module 屬性。此清單預設包含常用項目。

針對您的應用程式將此設定為最小的可能清單將會節省 JS 程式碼大小。例如,如果您未使用任何 Module 屬性,則可以使用 -sINCOMING_MODULE_JS_API=[] 進行建置。或者,如果您只使用少數幾個,則可以像這樣將它們列出:-sINCOMING_MODULE_JS_API=print,printErr

影響執行

下列 Module 屬性會影響程式碼執行。設定它們以自訂行為。

Module.arguments

命令列引數。arguments 的值包含如果編譯程式碼檢查 argcargv 時傳回的值。

Module.buffer

允許您提供自己的 ArrayBufferSharedArrayBuffer 以用作記憶體。

注意

只有在 -sWASM=0 時才支援此功能。如需 WebAssembly 支援,請參閱 Module.wasmMemory

Module.wasmMemory

允許您提供自己的 WebAssembly.Memory 以用作記憶體。用於初始化記憶體的屬性應符合編譯器選項。

例如,如果您在沒有記憶體成長的情況下將 INITIAL_MEMORY 設定為 8MB,則您提供的 wasmMemory(如果有的話)應該將 'initial''maximum' 都設定為 128(由於 WASM 頁面大小為 64KB)。

Module.locateFile

如果設定此方法,則當執行階段需要載入檔案時(例如 .wasm WebAssembly 檔案、.mem 記憶體初始化檔案,或檔案封裝器產生的檔案),將會呼叫此方法。此函式會接收在建置過程中設定的檔案相對路徑,以及 prefix(主 JavaScript 檔案目錄的路徑),並應傳回實際的 URL。這可讓您將檔案包或 .mem 檔案等託管在與 JavaScript 檔案目錄不同的位置(預設情況下),例如,如果您想要將它們託管在 CDN 上。

注意

如果我們在載入主 JavaScript 之前呼叫 locateFile,則 prefix 可能會是空字串。例如,如果預先載入檔案包或記憶體初始化檔案(可能從 HTML 中載入,在載入主 JavaScript 之前),就可能發生這種情況。

注意

為了支援 locateFile,已棄用數個 Module.*PrefixURL 選項,包括 memoryInitializerPrefixURLpthreadMainPrefixURLcdInitializerPrefixURLfilePackagePrefixURL。要更新您的程式碼,例如,如果您使用的 Module.memoryInitializerPrefixURL 等於 "https://mycdn.com/memory-init-dir/",則可以用類似以下的方式取代:

Module['locateFile'] = function(path, prefix) {
  // if it's a mem init file, use a custom dir
  if (path.endsWith(".mem")) return "https://mycdn.com/memory-init-dir/" + path;
  // otherwise, use the default, the prefix (JS file's dir) + the path
  return prefix + path;
}
Module.logReadFiles

如果設定此項,則當讀取任何檔案時,stderr 將會記錄。

Module.printWithColors

控制 Emscripten 執行階段程式庫是否嘗試使用顏色列印。目前,這僅會影響消毒器。

如果未設定,則如果列印到具有 node 的終端機,將會啟用顏色。

如果設定為 true,則如果可能,將永遠使用顏色。如果設定為 false,則永遠不會使用顏色。

Module.onAbort

如果設定此函式,則當發生異常程式終止時會呼叫此函式。這可能是因為直接呼叫 C 方法 abort()、從 JavaScript 呼叫,或因為在啟動期間無法擷取必要檔案(例如 Wasm 二進位檔)等嚴重問題所導致。在呼叫此函式後,程式會終止(也就是說,您無法使用它來嘗試執行其他動作來取代停止;此處沒有復原的可能性)。

Module.onRuntimeInitialized

如果設定此函式,則當執行階段完全初始化時會呼叫此函式,也就是說,編譯的程式碼可以安全執行,這是在任何非同步啟動操作完成之後(例如,非同步 WebAssembly 編譯、檔案預先載入等)。(等待呼叫此函式的替代方法是等待呼叫 main()。)

Module.noExitRuntime

如果 noExitRuntime 設定為 true,則在 run 完成後不會關閉執行階段。關閉執行階段會呼叫關閉回呼,例如 atexit 呼叫。如果您想要在 run() 完成後繼續使用程式碼,則必須設定此項。如果您使用暗示您希望不關閉執行階段的 API 命令,例如 emscripten_set_main_loop,則會自動為您設定此項。

Module.noInitialRun

如果 noInitialRun 設定為 true,則不會自動呼叫 main()(您稍後可以自行執行)。程式仍然會呼叫全域初始化程式、設定記憶體初始化等等。

Module.preInit

必須在全域初始化程式執行之前,但在 JavaScript 執行階段的基本初始化之後呼叫的函式(或函式陣列)。這通常用於檔案系統操作

Module.preinitializedWebGLContext

如果使用 -sGL_PREINITIALIZED_CONTEXT 設定進行建置,您可以將 Module.preinitializedWebGLContext 設定為預先建立的 WebGL 內容執行個體,稍後在 C/C++ 端初始化 WebGL 時將會使用它。如果要在執行其他頁面啟動動作的同時執行 GL 端載入(著色器編譯、材質載入等),和/或偵測 WebGL 功能支援(例如 GL 版本或壓縮材質支援),則預先建立 GL 內容非常有用,在載入任何編譯的程式碼之前或在與之並行時執行。

Module.preRun

在呼叫 run() 之前,但在定義和設定環境(包括全域初始化程式)之後,要呼叫的函式陣列。例如,這適用於使用檔案系統 API 設定目錄和檔案 — 因為這需要在載入檔案系統 API 之後,但在程式開始執行之前執行。

注意

如果程式碼需要影響全域初始化程式,則應改用 preInit 來執行。

Module.print

當將內容列印到標準輸出 (stdout) 時呼叫

Module.printErr

當將內容列印到標準錯誤 (stderr) 時呼叫

Module.mainScriptUrlOrBlob

允許 pthread 工作執行緒或 WASM 工作執行緒從 URL 或 Blob 獨立載入主應用程式模組 JavaScript 檔案(例如 main.js)。建立 pthread 工作執行緒或 WASM 工作執行緒需要載入主應用程式模組 JavaScript 檔案(例如 main.js)。預設情況下,它們從 main.js 的 URL 載入 main.js 的內容。但是,如果 main.js 檔案是從 Blob 載入,則無法存取 main.js 的 URL。此外,當 main.js 由 Node.JS 模組捆綁器(例如 webpack)捆綁時,該指令碼的 URL 可能會錯誤,webpack 捆綁器後的 URL 會產生錯誤的 URL,例如 main.chunk.js

其他方法

Module.destroy(obj)

應呼叫此方法來銷毀使用WebIDL 繫結在 JavaScript 中建立的 C++ 物件。如果未呼叫此方法,物件可能會被垃圾回收,但不會呼叫其解構函式。

引數
  • obj – 要銷毀的 JavaScript 包裝 C++ 物件。

Module.getPreloadedPackage()

如果您想要手動管理 .data 檔案包的下載,以進行自訂快取、進度報告和錯誤處理行為,您可以實作 Module.getPreloadedPackage = function(remotePackageName, remotePackageSize) 回呼,將資料檔案的內容提供回檔案載入指令碼。此回呼的傳回值應為 Arraybuffer,其中包含下載的檔案資料內容。有關範例,請參閱檔案 test/manual_download_data.html 和測試 browser.test_preload_file_with_manual_data_download

Module.instantiateWasm()

在以 WebAssembly 為目標時,Module.instantiateWasm 是選用的使用者實作回呼函式,Emscripten 執行階段會呼叫此函式來執行 WebAssembly 實例化動作。呼叫回呼函式時會使用兩個參數:importssuccessCallbackimports 是一個 JS 物件,其中包含在實例化時需要傳遞至 WebAssembly 模組的所有函式匯入,且一旦實例化,此回呼函式應使用產生的 WebAssembly Instance 物件呼叫 successCallback()

實例化可以同步或非同步執行。此函式的傳回值應包含實例化 WebAssembly 模組的 exports 物件,如果實例化是非同步執行,則傳回空字典物件 {},如果實例化失敗,則傳回 false

當您有其他自訂非同步啟動動作或下載可以與 WebAssembly 編譯並行執行時,透過此函式覆寫 WebAssembly 實例化程序會很有用。實作此回呼可讓您並行執行所有這些操作。有關此建構如何運作的範例,請參閱檔案 test/manual_wasm_instantiate.html 和測試 browser.test_manual_wasm_instantiate

注意

如果使用 Module.instantiateWasm 覆寫 WebAssembly 的實例化,目前不支援 Sanitizer 或 Source Map。當啟用 Source Map 或 Sanitizer 時提供 Module.instantiateWasm,可能會導致 WebAssembly 實例化無法完成。

Module.onCustomMessage()

當使用 PROXY_TO_WORKER = 1 編譯時(請參閱 settings.js),這個回呼函式(應在客戶端和 Worker 的 Module 物件上實作)允許在 Web Worker 和主執行緒之間傳送自訂訊息和資料(使用 proxyClient.jsproxyWorker.js 中定義的 postCustomMessage 函式)。

Module.fetchSettings()

覆寫從網路擷取 Wasm 模組時使用的預設設定物件。此屬性預期為字串,預設值為 { credentials: 'same-origin' }