Webassembly Não Consegue Acessar o DOM. Como?

O que é o DOM? Eu tenho certeza que o Webassembly vai trazer desenvolvedores que não são familiares com o conceito de DOM, como eu. Este artigo explica o que eu aprendi a respeito do DOM e contém um pequeno programa Webassembly que mudará o conteúdo de um documento HTML.

DOM

DOM é a contração de Document Object Model, há uma definição oficial dada pela W3, você pode olhá-la, eu tenho certeza de que esta correta, bem, tem que estar, a definição é deles!

A definição da W3 é muito profunda para quem está dando a primeira olhada nele. É como ter que estudar biologia molecular quando você quer decidir que iogurte comprar…

DOM Scripting Web Design with JavaScript and the Document Object Model é um livro que me deu uma visão mais simples do DOM. O DOM é apenas uma representação de um documento, é um objeto que representa um documento. Ele também permite a modificação do documento. Se a palavra Mapa fosse usada em vez de Modelo, então seria claro que o DOM ajudaria encontrar os elementos (ou nós) dentro do documento. Que documento? O documento que o Browser está mostrando.

OK vou parar aqui, não espere, há mais dois fatos importantes, o DOM não é relacionado com nenhuma linguagem, e ele pertence ao browser.

Antes de escrever este artigo, eu havia prometido que manteria a definição em um paragrafo, e eu falhei…

Do ponto de vista do programador: O DOM é uma estrutura de dados e API que nos permite ler e modificar o documento sendo apresendado pelo browser. Muito mais simples

Porque Webassembly Não consegue Acessar o DOM?

Parece que o acesso do Webassembly ao DOM foi deixado de fora porque o acesso pode ser feito através do JavaScript, e não havia tempo hábil para que esta característica estivesse implementada até o lançamento do MVP. Não há nenhum problema fundamental que poderia impedir o acesso do DOM pelo Webassembly, e esta característica esta road map.

Com isso em mãos, vamos fazer alguma coisa com o Webassembly.

Usando o Webassembly Para Alterar o Valor de um Botão

O valor de um botão é parte do DOM. No exemplo seguinte nós criamos um documento HTML que define um botão com uma mensagem default ("click here to see wasm changing this message"), também temos uma função Webassembly que mudará este valor. O novo valor mostrará quantas vezes o botão foi clicado. A variável que mantém este contador é definido dentro do módulo Webassembly. Nós também explicamos como EMSCRIPTEN faz este processo ficar fácil.

O seguinte código HTML(conteúdo do arquivo dom.html), muito simples, ele basicamente define um botão, carrega o módulo Webassembly e executa a função IncrementClickCountOnValue() quando o botão é clicado.


<html>
<head>
  <script type="text/javascript" src="dom.js"></script>
  <script>
  
    // EMSCRIPTEN "-s MODULARIZED=1" option makes it easy to load a webassembly module,
    // it generates a .js file with a Module() function that does the job.
    // The .js file also puts some glue code that allows changing the DOM from within
    // the Webassembly code (through JavaScript)
    Module()
    .then(function(instance){
        var exports = instance['asm']; // the .js file puts the exports in the 'asm' field
        var IncrementClickCountOnValue = exports._IncrementClickCountOnValue;
        // Add button listener
        var button = document.getElementById('run');
        button.addEventListener('click', function() {
            // .
            // Finally, the wasm code being called here, it changes the button value!
            // .
            IncrementClickCountOnValue();
        }, false);
      }
  );
  </script>
</head>
<body>
  <input type="button" id="run" value="click here to see wasm changing this message"/>
</body>
</html>

O seguinte código C(conteúdo de dom.c), tem apenas uma função, ela usa a EM_ASM_ interface. Dê uma olhada nos comentários para uma explanação mais detalhada.


//
// This function will change the HTML value of a node(or element) that has id=run
//
// Important things to note:
//
// EMSCRIPTEN_KEEPALIVE
//  It forces this function to be present in the webassembly module.
//  There is no reference to this function in the module, the optimization would
//  wipe it out as it appears to be dead code.
//  This function is called from Javascript though
//
// EM_ASM_
//  EMSCRIPTEN macro that does all the interface with Javascript by us.
//  It creates a function inside the generated javascript file and call it from
//  here.
//  Generated function from the Javascript file:
//  var ASM_CONSTS = [function($0) { document.getElementById("run").value='Webassembly click count: '+$0 }];
// 
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;
}

Compilando:


emcc dom.c -O1 -s MODULARIZE=1 -s WASM=1 -o dom.js


Esta compilação pega o arquivo dom.c e gera estes dois arquivos:

  • dom.js contém o çódigo auxiliar gerado por EMSCRIPTEN. Importante notar que ele contém a função Module() que carrega o módulo Webassembly. Ele também contém as funções Javascript geradas por EM_ASM_. Note que é a opção "-s MODULARIZE=1" que pede a EMSCRIPTEN para que a função Module() seja gerada, o código fica muito mais limpo com esta opção.

  • dom.wasm contém o módulo Webassembly.

Uma nota sobre otimização. Eu geralmente uso a opção -O1 porque um humano consegue ler o código gerado, -Oz gera um código difícil de ler. Comparação entre opção de otimização e tamanho de arquivo:

Arquivo -O1 -Oz %
dom.js 66,535 bytes 16,916 bytes 74 % redução
dom.wasm 10,182 bytes 221 bytes 98 % redução

Para executar este código, apenas rode emrun para servir a nossa página e enderece o browser para: http://localhost:8080/dom.html


emrun --no_browser --port 8080 .

Conclusão

Foi surpreendentemente fácil modificar o DOM de dentro de Webassembly, EMSCRIPTEN faz todo o trabalho para nós. Esta é uma área que mudará muito no futuro, então talvez seja sábio concentrar todo o código que faz interface com o DOM em um arquivo porque quando acessar o DOM nativamente do Webassembly se tornar uma realidade, será fácil portar as macros EMSCRIPTEN para o novo método.


Leave a message below. Webassembly is evolving rapidly, please let me know if this post got outdated.

Enjoyed this post?

Don't miss new posts: Share it with your friends:

2 Resultados

  1. Eduardo disse:

    Que massa! Irei dar uma lida em casa

    • webassemblycodecom-admin disse:

      Legal!
      Nao esquece de deixar comentarios e compartilhar para outras pessoas que possam se interessar pelo assunto. Obrigado!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *