A memória JavaScript armazena todos os dados e instruções usados ​​durante o desenvolvimento do programa e o tempo de execução na forma binária. JavaScript, também conhecido como ECMAScript , é uma linguagem gerenciada por memória .

O mecanismo JavaScript acessa e gerencia a memória por si mesmo e aloca memória para cada programa ou pedaço de código escrito e executado. Ele também realiza a coleta de lixo de dados que não são mais encontrados na memória.

Embora o JavaScript seja uma linguagem gerenciada por memória, ele também ajuda a gerenciar os dados. Mas tem falhas. Por exemplo, o JavaScript pode alocar mais do que o espaço livre necessário na memória para um determinado programa ou variável. Em alguns casos, a coleta de lixo em JavaScript pode ser lenta.

Para dar aos desenvolvedores a capacidade de alocar e compartilhar dados em visualizações (usando matrizes digitadas) entre vários threads de uma memória, os recursos ArrayBuffer e SharedArrayBuffer foram introduzidos .

O que é SharedArrayBuffer ?

Ao discutir SharedArrayBuffer , podemos facilmente nos concentrar nas palavras físicas: “shared,” “array” e “buffer”.

Um array é uma estrutura de dados usada na programação para armazenar elementos de dados que consistem em diferentes tipos de dados (strings, booleanos, números e objetos). Um buffer é parte do armazenamento de memória usado para armazenar dados temporariamente antes de serem enviados ou recebidos para uso.

ArrayBuffer é uma matriz diferente de qualquer outra-é uma matriz de bytes, o que significa que apenas bytes são aceitos.

Para usar memória compartilhada em JavaScript, você precisa criar o SharedArrayBuffer . Isso é feito usando o objeto SharedArrayBuffer , que cria um novo construtor de objeto para gravar e compartilhar dados entre vários threads.

O histórico de SharedArrayBuffer

Em 5 de janeiro de 2018, SharedArrayBuffer foi desativado em todos os principais navegadores devido a um ataque de vulnerabilidade encontrado no Arquitetura da CPU .

Desde então, SharedArrayBuffer foi reativado no Google Chrome v67 e agora pode ser usado em plataformas que têm seu recurso de isolamento de site ativado, que abordaremos em uma seção subsequente deste artigo. Esta atualização protege contra o ataque de vulnerabilidade Spectre e torna seu site mais seguro.

A seguir, vamos explorar como compartilhar memória usando SharedArrayBuffer em JavaScript. Primeiro, vamos compartilhar a memória, depois atualizá-la e sincronizá-la e, finalmente, depurá-la.

Compartilhando memória usando SharedArrayBuffer em JavaScript

Uma das vantagens de usar SharedArrayBuffer é a capacidade de compartilhar memória em JavaScript. Em JavaScript, web workers atendem como meio de criar threads no código JS.

No entanto, os web workers também são usados ​​lado a lado com SharedArrayBuffer , que permite o compartilhamento de dados binários brutos entre os web workers apontando diretamente para a memória onde cada dado foi armazenado ou acessado anteriormente.

Vamos dar uma olhada em um exemplo de como compartilhar memória usando SharedArrayBuffer .

Antes de começar, crie três arquivos: index.html (onde vinculamos os scripts), script.js (thread principal) e trabalhador. js (thread de trabalho).

      usando buffer de array compartilhado       

Dê uma olhada no console do seu navegador:)

Vejamos o tópico principal (o arquivo script.js) primeiro. Aqui, acessamos worker.js e criamos uma memória compartilhada usando o SharedArrayBuffer objeto e defina seus bytes por comprimento para 1024 (observação: qualquer byte necessário por comprimento pode ser usado).

Usando uma matriz digitada do tipo Int16Array para interpretar os dados que estão sendo passados, atribuímos um número ao array digitado ( 20 ) para ser compartilhado a partir do thread principal. Enviamos o buffer para o thread de trabalho com o uso de postMessage .

/* LINHA PRINCIPAL */ const newWorker=new Worker ('worker.js');
const buffMemLength=novo SharedArrayBuffer (1024);//comprimento do byte
deixe typedArr=new Int16Array (buffMemLength);
//dados originais
typedArr [0]=20;
//enviando o buffer para o trabalhador
newWorker.postMessage (buffMemLength);

Para compartilhar os dados do thread principal com o thread de trabalho, definimos um eventListener para ser executado quando os dados forem recebidos. Aqui, observe que estamos usando uma matriz digitada Int16 para exibir os dados no console do navegador.

/* LINHA DE TRABALHO */ addEventListener ('message', ({data})=> { deixe arr=new Int16Array (dados); console.group ('[o thread de trabalho]'); console.log ('Dados recebidos do thread principal:% i', arr [0]); console.groupEnd (); postMessage ('Atualizado');
})

No console do seu navegador, você deve ver o seguinte:

 [o thread de trabalho] worker.js: 7
Dados recebidos do thread principal: 20 worker.js: 8

Atualizando e sincronizando a memória compartilhada

Desde a adição de SharedArrayBuffer ao JavaScript, atualizar a memória compartilhada se tornou mais fácil. Usando o exemplo anterior, vamos atualizar os dados do thread de trabalho.

Vamos definir o arr [0] original do thread principal para a variável dataChanged declarada acima no escopo (no thread de trabalho).

/* LINHA DE TRABALHO */ deixe BYTE_PER_LENTH=5;
addEventListener ('message', ({data})=> { var arr=novo Int16Array (dados); console.group ('[thread de trabalho]'); console.log ('Dados recebidos do thread principal:% i', arr [0]); console.groupEnd (); //atualizando os dados do thread de trabalho deixe dataChanged=5 * BYTE_PER_LENTH; arr [0]=dataChanged; //Enviando para o tópico principal postMessage ('Atualizado');
})

Para que os dados sejam atualizados a partir do thread de trabalho, chamamos um evento onmessage que será disparado no thread principal, indicando que os dados foram atualizados a partir do thread de trabalho.

/* LINHA PRINCIPAL */ const newWorker=new Worker ('worker.js');
const buffMemLength=novo SharedArrayBuffer (1024);//comprimento do byte
var typedArr=new Int16Array (buffMemLength);
//dados originais
typedArr [0]=20;
//enviando o buffer para o trabalhador
newWorker.postMessage (buffMemLength); //evento onmessage
newWorker.onmessage=(e)=> { console.group ('[o tópico principal]'); console.log ('Dados atualizados do thread de trabalho:% i', typedArr [0]); console.groupEnd ();
}

No console do navegador, você verá:

 [o thread de trabalho] worker.js: 7
Dados recebidos do thread principal: 20 worker.js: 8
[o tópico principal] script.js: 15
Dados atualizados do thread de trabalho: 25 script.js: 16

A sincronização da memória compartilhada é importante porque, quando implementada, a sincronização faz com que a memória compartilhada seja executada simultaneamente sem ser alterada. Para incorporar a sincronização na memória compartilhada, os desenvolvedores usam Operações atômicas .

Atomics garante que cada processo seja executado consecutivamente antes do próximo, e que todos os dados que foram lidos de uma memória ou gravados em uma memória particular sejam executados um após o outro com a ajuda do wait () e notification () .

Atualizações recentes em SharedArrayBuffer e isolamento de origem cruzada

Desde maio de 2021, houve várias atualizações críticas para a memória compartilhada-incluindo o isolamento de origem cruzada-em JavaScript que permite aos desenvolvedores depurar a memória compartilhada com mais eficiência. Atualmente é compatível com Firefox 79+ e no Chrome para desktop, mas as atualizações do Chrome 92 estarão acessíveis para sites com páginas isoladas de origem cruzada.

Para implementar SharedArrayBuffer , você precisa de um ambiente seguro que limite o acesso usando uma ou mais diretivas de cabeçalho de resposta. Isso é chamado de isolamento de origem cruzada e, apesar do uso anteriormente desencorajado de memória compartilhada, provou ser a melhor maneira de proteger seu site.

O que é isolamento de origem cruzada?

O isolamento de origem cruzada é um novo recurso de segurança (desde abril de 2021) que foi adicionado ao navegador. Resumindo, é o resultado do envio de dois cabeçalhos HTTP em seu documento de nível superior (COOP e COEP). Esses cabeçalhos permitem que seu site tenha acesso a APIs da web, como SharedArrayBuffer , e evite ataques externos (ataques Specter, ataques de origem cruzada e semelhantes).

Anteriormente, os sites que usavam memória compartilhada podiam carregar conteúdo de origem cruzada sem permissão. Esses sites podem interagir com janelas pop-ups que não são da mesma origem, podendo causar uma violação de segurança ou uma brecha para obter acesso às informações do usuário no site. Para sites que usam memória compartilhada, é muito importante estar seguro e também proteger as informações do usuário.

Habilitando o isolamento de origem cruzada em seu site

Agora que sabemos mais sobre o contexto do isolamento de origem cruzada, vamos ativá-lo em nosso site.

Primeiro, habilite o cabeçalho cross-origin-opener-policy (COOP) no nível superior do seu documento, com mesma origem :

 Cross-Origin-Opener-Policy: same-origin

Este cabeçalho isola a página de quaisquer pop-ups de origem cruzada no navegador para que eles não possam acessar documentos ou enviar mensagens diretas para eles. Ele também garante que sua página esteja em um contexto seguro com páginas com as mesmas origens de nível superior.

Em seguida, envie um cabeçalho de política de incorporação de origem cruzada (COEP) com um valor indicando require-CORP (política de recurso de origem cruzada).

 Cross-Origin-Embedder-Policy: require-corp

Isso garante que todos os recursos carregados de seu site tenham sido carregados com CORP. O cabeçalho COEP quebra todas as integrações que exigem comunicação com janelas de origem cruzada no navegador, como autenticações de servidores de terceiros e pagamentos (checkouts).

Ao definir esses cabeçalhos no nível superior de seus documentos, seu site agora está em um contexto seguro e fornece acesso ao uso de APIs da web.

A postagem Noções básicas sobre SharedArrayBuffer e cruzar-o isolamento da origem apareceu primeiro no LogRocket Blog .