Как я могу получить доступ к DOM из текстового формата WebAssembly? - PullRequest
0 голосов
/ 29 августа 2018

В этой статье показано, как получить доступ к DOM в WebAssembly из программы на C:

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

unsigned int EMSCRIPTEN_KEEPALIVE IncrementClickCountOnValue()
{
    // Static variable that hold how many times this function was clicked
    static int clicks=0;

    // Modify the DOM, through a Javascript call provided by EM_ASM_, getElementById  is the DOM API used
    EM_ASM_( {document.getElementById("run").value='Webassembly click count: '+$0}, ++clicks );
    return 1;
}

Если вы скомпилируете (emcc dom.c -O1 -s MODULARIZE=1 -s WASM=1 -o dom.js) и запустите его (emrun --no_browser --port 8080 .), он будет работать как положено.

Как я могу сделать то же самое без C, я. е. что будет эквивалентно EM_ASM_( {document.getElementById("run").value='Webassembly click count: '+$0}, ++clicks ); в текстовом формате WebAssembly ?

1 Ответ

0 голосов
/ 29 августа 2018

Нет эквивалента в текстовом формате WebAssembly, потому что среда WebAssembly ничего не знает о DOM (или любом из API-интерфейсов браузера) или о том, как им манипулировать.

Что может сделать WebAssembly - это импортировать функции из своего хоста, такого как браузер. Затем вы можете вызвать эти функции из WebAssembly с помощью инструкции call, указав импортированный индекс функции или по имени.

Вот пример увеличения статического (глобального) в WebAssembly и последующего обновления DOM на основе счетчика:

;; clicks.wat

(module

    ;; import the updateClickCount function from JavaScript land

    (import "button" "updateClickCount"
        (func $updateClickCount
            (param $x i32)
        )
    )

    ;; Define a mutable static i32 initialized at 0

    (global $count (mut i32) (i32.const 0))

    ;; Define and export a function to JS land

    (func (export "onClick")

        ;; Increment the global count

        get_global $count
        i32.const 1
        i32.add
        set_global $count

        ;; Push the count on the stack and call the imported function

        get_global $count
        call $updateClickCount
    )
)

Это может быть соответствующий HTML / JS для загрузки и настройки импорта и подключения к DOM:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Clicks</title>
</head>
<body>

    <button id="click">CLICK ME</button>
    <p id="numclicks"></p>

    <script>

        // This is what we'll make available to wasm

        const imports = {
            button: {
                updateClickCount: (num) => document.getElementById('numclicks').innerHTML = num.toString()
            }
        };

        WebAssembly.instantiateStreaming(fetch('clicks.wasm'), imports)
            .then(obj => {

                const exports = obj.instance.exports;

                // When the button is clicked, call the function in wasm

              document.getElementById('click').addEventListener('click', () => {

                    exports.onClick();
                });

            }).catch((err) => console.error(err));
    </script>
</body>
</html>

Пример студии WebAssembly (нажмите «Создать и запустить»): https://webassembly.studio/?f=ff0fei4xgd9

...