O suporte à 
tecnologia WebAssembly (Wasm) apareceu nos navegadores há relativamente pouco tempo. Mas essa tecnologia pode expandir os recursos da Web, tornando-a uma plataforma capaz de suportar aplicativos que geralmente são vistos como desktop.
Dominar o WebAssembly pode ser uma tarefa assustadora para desenvolvedores da web. No entanto, o compilador 
AssemblyScript pode melhorar a situação.
O autor do artigo, que estamos publicando a tradução de hoje, oferece primeiro para falar sobre por que o WebAssembly é uma tecnologia muito promissora e, em seguida, ver como o AssemblyScript pode ajudar a desbloquear o potencial de Wasm.
Webassembly
O WebAssembly pode ser chamado de idioma de baixo nível para navegadores. Ele oferece aos desenvolvedores a capacidade de criar código compilado em algo que não seja JavaScript. Isso permite que os programas incluídos nas páginas da Web funcionem quase tão rápido quanto os aplicativos nativos para várias plataformas. Esses programas são executados em um ambiente limitado e seguro.
Representantes das equipes responsáveis pelo desenvolvimento de todos os principais navegadores (Chrome, Firefox, Safari e Edge) participaram da criação do padrão WebAssembly. Eles concordaram em uma 
arquitetura de sistema no início de 2017. Agora, todos os navegadores acima oferecem suporte ao WebAssembly. De fato, essa tecnologia pode ser usada em 
aproximadamente 87% dos navegadores.
O código do WebAssembly existe em formato binário. Isso significa que esse código é menor que o código JavaScript semelhante e é carregado mais rapidamente. Além disso, o código Wasm pode ser apresentado em 
formato de texto , para que as pessoas possam ler e editar.
Quando o padrão WebAssembly apareceu pela primeira vez, alguns desenvolvedores pensaram que ele poderia substituir o JavaScript e se tornar o idioma principal da web. Mas o WebAssembly é melhor visto como uma nova ferramenta que se integra bem à plataforma da web existente. Este é um dos seus 
objetivos prioritários .
Em vez de substituir o JavaScript, onde esse idioma é usado há muito tempo e com sucesso, o WebAssembly oferece novas oportunidades interessantes para desenvolvedores da web. É verdade que o código Wasm não tem acesso direto ao DOM, portanto, a maioria dos projetos da Web existentes continuará usando JavaScript. Essa linguagem, ao longo dos anos de desenvolvimento e otimização, já é bastante rápida. E o WebAssembly tem seus próprios 
aplicativos :
- Jogos
- Cálculos científicos, visualizações, simulações.
- Aplicações CAD.
- Editando imagens e vídeos.
Todos esses usos para Wasm são unidos pelo que seus respectivos aplicativos geralmente são considerados desktop. Porém, devido ao fato do WebAssembly permitir que você atinja um nível de desempenho próximo ao nativo, muitos aplicativos semelhantes agora podem ser implementados usando a plataforma da web.
O WebAssembly pode tirar proveito dos projetos da web existentes. Um exemplo é o projeto 
Figma . Graças ao uso do Wasm, o tempo de carregamento deste projeto foi significativamente aprimorado. Se um site usa código que executa cálculos pesados, então, para melhorar o desempenho deste site, faz sentido substituir apenas esse código por um análogo do WebAssembly.
Você pode tentar usar o WebAssembly em seus próprios projetos. Este idioma pode ser aprendido e escrito 
imediatamente nele . Porém, o WebAssembly foi desenvolvido originalmente como um 
destino de compilação para outros idiomas. Foi 
projetado com bom suporte para C e C ++. O 
suporte experimental Wasm apareceu no Go 1.11. Está sendo feito muito esforço para escrever aplicativos Wasm no 
Rust .
Mas é perfeitamente possível que os desenvolvedores da Web não desejem aprender C, C ++, Go ou Rust apenas para usar o WebAssembly. O que eles fazem? A resposta a esta pergunta pode dar ao AssemblyScript.
AssemblyScript
O AssemblyScript é um compilador que converte o código TypeScript em código do WebAssembly. TypeScript é uma linguagem desenvolvida pela Microsoft. Este é um superconjunto de JavaScript, com suporte aprimorado a tipos e alguns outros recursos. O TypeScript se tornou uma linguagem bastante 
popular . Note-se que o AssemblyScript pode converter em Wasm apenas um conjunto limitado de construções TypeScript. Isso significa que mesmo alguém que não conhece o TypeScript pode aprender rapidamente essa linguagem em um nível suficiente para escrever o código que o AssemblyScript entende.
Além disso, como o TypeScript é muito semelhante ao JavaScript, podemos dizer que a tecnologia AssemblyScript permite que os desenvolvedores da Web integrem facilmente módulos Wasm em seus projetos sem a necessidade de aprender uma linguagem completamente nova.
Exemplo
Vamos escrever nosso primeiro módulo AssemblyScript. Todo o código que discutiremos agora pode ser encontrado no 
GitHub . Para dar 
suporte ao WebAssembly, precisamos pelo menos do 
Node.js 8.
Crie um novo diretório, inicialize o projeto npm e instale o AssemblyScript:
mkdir assemblyscript-demo cd assemblyscript-demo npm init npm install --save-dev github:AssemblyScript/assemblyscript 
Observe que o AssemblyScript deve ser instalado diretamente 
no repositório GitHub do projeto. O AssemblyScript ainda não foi publicado no npm, pois os desenvolvedores 
ainda não o consideram pronto para uso generalizado.
asinit arquivos auxiliares usando o comando 
asinit incluído no AssemblyScript:
 npx asinit . 
Agora a seção de 
scripts do nosso 
package.json deve assumir o seguinte formato:
 {  "scripts": {    "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",    "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",    "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"  } } 
O arquivo 
index.js localizado na pasta raiz do projeto terá a seguinte aparência:
 const fs = require("fs"); const compiled = new WebAssembly.Module(fs.readFileSync(__dirname + "/build/optimized.wasm")); const imports = {  env: {    abort(_msg, _file, line, column) {       console.error("abort called at index.ts:" + line + ":" + column);    }  } }; Object.defineProperty(module, "exports", {  get: () => new WebAssembly.Instance(compiled, imports).exports }); 
Isso permite incluir módulos WebAssembly no seu código usando o comando 
require . Ou seja - da mesma maneira que os módulos JavaScript regulares estão conectados.
A pasta de 
assembly contém o arquivo 
index.ts . Possui código-fonte escrito de acordo com as regras do AssemblyScript. O código clichê gerado automaticamente é uma função simples para adicionar dois números:
 export function add(a: i32, b: i32): i32 {  return a + b; } 
Talvez você esperasse que a assinatura de uma função semelhante se parecesse com 
add(a: number, b: number): number . Portanto, parece que ele foi escrito em TypeScript comum. Mas aqui, em vez do 
number do tipo, o tipo 
i32 . Isso acontece porque o código AssemblyScript usa 
tipos WebAssembly específicos para números inteiros e de ponto flutuante, em vez do tipo de 
número genérico do TypeScript.
Vamos montar o projeto:
 npm run asbuild 
Os seguintes arquivos devem aparecer na pasta de 
build :
 optimized.wasm optimized.wasm.map optimized.wat untouched.wasm untouched.wasm.map untouched.wat 
Existem versões otimizadas e regulares da montagem. Cada versão do assembly nos fornece um arquivo .wasm binário, um 
mapa .wasm.map do 
mapa e uma representação textual do código binário em um arquivo .wat. A apresentação de teste do código Wasm é destinada ao programador, mas nem olharemos para este arquivo. Na verdade, uma das razões para usar o AssemblyScript é que elimina a necessidade de trabalhar com o código Wasm.
Agora, vamos executar o Node.js no modo REPL e garantir que o módulo Wasm compilado possa ser usado da mesma maneira que qualquer módulo JS comum:
 $ node Welcome to Node.js v12.10.0. Type ".help" for more information. > const add = require('./index').add; undefined > add(3, 5) 8 
Em geral, isso é tudo o que é necessário para usar a tecnologia WebAssembly no Node.js.
Equipando um projeto com um script observador
Para reconstruir automaticamente o módulo durante o desenvolvimento ao fazer alterações, recomendo usar o pacote 
onchange . O fato é que o AssemblyScript 
ainda não possui seu próprio sistema para monitorar alterações no arquivo. Instale o pacote onchange:
 npm install --save-dev onchange 
Adicione o script 
asbuild:watch ao 
package.json . 
O sinalizador -i é incluído no comando para que o processo de construção inicie uma vez quando o script for chamado, antes que ocorram eventos.
 {  "scripts": {    "asbuild:untouched": "asc assembly/index.ts -b build/untouched.wasm -t build/untouched.wat --sourceMap --validate --debug",    "asbuild:optimized": "asc assembly/index.ts -b build/optimized.wasm -t build/optimized.wat --sourceMap --validate --optimize",    "asbuild": "npm run asbuild:untouched && npm run asbuild:optimized",    "asbuild:watch": "onchange -i 'assembly/**/*' -- npm run asbuild"  } } 
Agora, em vez de executar constantemente o comando 
asbuild , basta executar o 
asbuild:watch uma vez.
Desempenho
Escreveremos um teste simples que avaliará o nível de desempenho do código Wasm. O principal escopo do WebAssembly é resolver tarefas que usam o processador intensivamente. Por exemplo, esses são alguns tipos de cálculos "pesados". Vamos criar uma função que descubra se um determinado número é primo.
A implementação básica de JS de uma função semelhante é mostrada abaixo. É organizado de maneira muito simples, verifica o número por força bruta, mas, para nossos propósitos, é adequado, pois realiza grandes quantidades de cálculos.
 function isPrime(x) {    if (x < 2) {        return false;    }    for (let i = 2; i < x; i++) {        if (x % i === 0) {            return false;        }    }    return true; } 
Uma função semelhante, escrita para o compilador AssemblyScript, parece quase a mesma. A principal diferença é a presença de anotações de tipo no código:
 function isPrime(x: u32): bool {    if (x < 2) {        return false;    }    for (let i: u32 = 2; i < x; i++) {        if (x % i === 0) {            return false;        }    }    return true; } 
Para analisar o desempenho do código, usaremos o pacote 
Benchmark.js . Instale-o:
 npm install --save-dev benchmark 
Crie o arquivo 
benchmark.js :
 const Benchmark = require('benchmark'); const assemblyScriptIsPrime = require('./index').isPrime; function isPrime(x) {    for (let i = 2; i < x; i++) {        if (x % i === 0) {            return false;        }    }    return true; } const suite = new Benchmark.Suite; const startNumber = 2; const stopNumber = 10000; suite.add('AssemblyScript isPrime', function () {    for (let i = startNumber; i < stopNumber; i++) {        assemblyScriptIsPrime(i);    } }).add('JavaScript isPrime', function () {    for (let i = startNumber; i < stopNumber; i++) {        isPrime(i);    } }).on('cycle', function (event) {    console.log(String(event.target)); }).on('complete', function () {    const fastest = this.filter('fastest');    const slowest = this.filter('slowest');    const difference = (fastest.map('hz') - slowest.map('hz')) / slowest.map('hz') * 100;    console.log(`${fastest.map('name')} is ~${difference.toFixed(1)}% faster.`); }).run(); 
Aqui está o que eu consegui obter após executar o comando 
node benchmark do 
node benchmark no meu computador:
 AssemblyScript isPrime x 74.00 ops/sec ±0.43% (76 runs sampled) JavaScript isPrime x 61.56 ops/sec ±0.30% (64 runs sampled) AssemblyScript isPrime is ~20.2% faster. 
Como você pode ver, a implementação do algoritmo AssemblyScript foi 20% mais rápida que a implementação do JS. No entanto, observe que este teste é uma 
marca de microbench . Não confie demais em seus resultados.
Para encontrar resultados mais confiáveis da pesquisa de desempenho dos projetos AssemblyScript - eu recomendo dar uma olhada 
neste e 
neste benchmark.
Usando um módulo Wasm em uma página da Web
Vamos usar o nosso módulo Wasm em uma página da web. Começamos criando um arquivo 
index.html com o seguinte conteúdo:
 <!DOCTYPE html> <html>    <head>        <meta charset="utf-8" />        <title>AssemblyScript isPrime demo</title>    </head>    <body>        <form id="prime-checker">            <label for="number">Enter a number to check if it is prime:</label>            <input name="number" type="number" />            <button type="submit">Submit</button>        </form>        <p id="result"></p>        <script src="demo.js"></script>    </body> </html> 
Agora crie o arquivo 
demo.js cujo código é mostrado abaixo. Existem 
várias maneiras de carregar os módulos WebAssembly. O mais eficiente é compilar e inicializar no modo de streaming usando a função 
WebAssembly.instantiateStreaming . Observe que precisaremos redefinir a função 
abort , que é chamada se alguma 
instrução não 
for executada.
 (async () => {    const importObject = {        env: {            abort(_msg, _file, line, column) {                console.error("abort called at index.ts:" + line + ":" + column);            }        }    };    const module = await WebAssembly.instantiateStreaming(        fetch("build/optimized.wasm"),        importObject    );    const isPrime = module.instance.exports.isPrime;    const result = document.querySelector("#result");    document.querySelector("#prime-checker").addEventListener("submit", event => {        event.preventDefault();        result.innerText = "";        const number = event.target.elements.number.value;        result.innerText = `${number} is ${isPrime(number) ? '' : 'not '}prime.`;    }); })(); 
Em seguida, instale o pacote do 
servidor estático . Precisamos de um servidor devido ao fato de que, para usar a função 
WebAssembly.instantiateStreaming , o módulo deve ser atendido usando o tipo MIME 
application/wasm .
 npm install --save-dev static-server 
Adicione o script apropriado ao 
package.json :
 {  "scripts": {    "serve-demo": "static-server"  } } 
Agora 
npm run serve-demo e abra o URL do host local no navegador. Se você digitar um determinado número no formulário, poderá descobrir se é simples ou não. Agora, ao desenvolver o AssemblyScript, percorremos um longo caminho desde a escrita do código até seu uso no Node.js. e em uma página da web.
Sumário
O WebAssembly e, portanto, o AssemblyScript, não conseguem, de alguma forma, acelerar qualquer site magicamente. Mas Wasm nunca foi encarregado de acelerar absolutamente tudo. Essa tecnologia é notável, pois abre caminho para a web para novos tipos de aplicativos.
Algo semelhante pode ser dito sobre o AssemblyScript. Essa tecnologia simplifica o acesso ao WebAssembly para um grande número de desenvolvedores. Ele permite, ao criar código em uma linguagem próxima ao JavaScript, usar os recursos do WebAssembly para resolver problemas computacionais complexos.
Caros leitores! Como você avalia as perspectivas de uso do AssemblyScript em seus projetos?
