Quais são os usos reais da WeakMap
estrutura de dados introduzidos no ECMAScript 6?
Como uma chave de um mapa fraco cria uma forte referência ao seu valor correspondente, garantindo que um valor que foi inserido em um mapa fraco nunca desapareça enquanto sua chave ainda estiver ativa, ela não poderá ser usada para tabelas de notas, caches ou qualquer outra coisa para a qual você normalmente usaria referências fracas, mapas com valores fracos etc. para.
Parece-me que isto:
weakmap.set(key, value);
... é apenas uma maneira indireta de dizer isso:
key.value = value;
Que casos de uso concretos estão faltando?
javascript
ecmascript-6
weakmap
valderman
fonte
fonte
WeakMap
s pode ser usado para detectar vazamentos de memória: stevehanov.ca/blog/?id=148Respostas:
Fundamentalmente
O WeakMaps fornece uma maneira de estender objetos de fora sem interferir na coleta de lixo. Sempre que você deseja estender um objeto, mas não pode porque está selado - ou de uma fonte externa - um WeakMap pode ser aplicado.
Um WeakMap é um mapa (dicionário) em que as chaves são fracas - ou seja, se todas as referências à chave forem perdidas e não houver mais referências ao valor - o valor poderá ser coletado como lixo. Vamos mostrar isso primeiro por meio de exemplos, depois explicar um pouco e finalmente terminar com o uso real.
Digamos que estou usando uma API que me fornece um determinado objeto:
Agora, eu tenho um método que usa o objeto:
Quero acompanhar quantas vezes o método foi chamado com um determinado objeto e relatar se isso ocorrer mais de N vezes. Ingenuamente, alguém poderia pensar em usar um mapa:
Isso funciona, mas há um vazamento de memória - agora controlamos todos os objetos da biblioteca passados para a função que impede que os objetos da biblioteca sejam coletados como lixo. Em vez disso, podemos usar um
WeakMap
:E o vazamento de memória se foi.
Casos de uso
Alguns casos de uso que causariam um vazamento de memória e são ativados por
WeakMap
s incluem:Vamos olhar para um uso real
Pode ser usado para estender um objeto de fora. Vamos dar um exemplo prático (adaptado, meio real - para fazer um ponto) do mundo real do Node.js.
Digamos que você seja Node.js e tenha
Promise
objetos - agora você deseja acompanhar todas as promessas atualmente rejeitadas - no entanto, não deseja impedir que elas sejam coletadas como lixo, caso não exista referência a elas.Agora, você não deseja adicionar propriedades a objetos nativos por razões óbvias - para ficar preso. Se você mantiver referências às promessas, está causando um vazamento de memória, pois nenhuma coleta de lixo pode acontecer. Se você não mantiver referências, não poderá salvar informações adicionais sobre promessas individuais. Qualquer esquema que envolva salvar o ID de uma promessa significa inerentemente que você precisa de uma referência a ela.
Digite WeakMaps
WeakMaps significa que as teclas estão fracas. Não há maneiras de enumerar um mapa fraco ou obter todos os seus valores. Em um mapa fraco, você pode armazenar os dados com base em uma chave e, quando a chave é coletada como lixo, os valores também.
Isso significa que, dada uma promessa, você pode armazenar um estado sobre ele - e esse objeto ainda pode ser coletado como lixo. Posteriormente, se você receber uma referência a um objeto, poderá verificar se possui algum estado relacionado a ele e relatá-lo.
Isso foi usado para implementar ganchos de rejeição sem tratamento por Petka Antonov, como este :
Mantemos informações sobre promessas em um mapa e podemos saber quando uma promessa rejeitada foi tratada.
fonte
useObj
exemplo usando aMap
e não aWeakMap
, usamos o objeto passado como chave do mapa. O objeto nunca é removido do mapa (já que não saberíamos quando fazer isso), portanto sempre há uma referência a ele e nunca pode ser coletado como lixo. No exemplo WeakMap, assim que todas as outras referências ao objeto desaparecerem - o objeto pode ser limpo doWeakMap
. Se você ainda não tem certeza o que quero dizer por favor me avisecalled
exemplo é melhor escrito usando jsfiddle.net/f2efbm7z e não demonstra o uso de um mapa fraco. De fato, pode ser melhor escrito de um total de 6 maneiras, que listarei abaixo.p[key_symbol] = data
. ou 2) nomeação única;p.__key = data
. ou 3) escopo privado;(()=>{let data; p.Key = _=>data=_;})()
. ou 4) proxy com 1 ou 2 ou 3. ou 5) substituir / estender a classe Promise por 1 ou 2 ou 3. ou 6) substituir / estender a classe Promise por uma tupla de membros necessários. - Em qualquer caso, um mapa fraco não é necessário, a menos que você precise de um cache sensível à memória.Essa resposta parece ser tendenciosa e inutilizável em um cenário do mundo real. Leia como está e não a considere como uma opção real para outra coisa que não a experimentação
Um caso de uso pode ser usá-lo como um dicionário para ouvintes, tenho um colega de trabalho que fez isso. É muito útil porque qualquer ouvinte é direcionado diretamente para essa maneira de fazer as coisas. Adeus
listener.on
.Mas, de um ponto de vista mais abstrato,
WeakMap
é especialmente poderoso para desmaterializar o acesso a basicamente qualquer coisa, você não precisa de um espaço para nome para isolar seus membros, pois ele já está implícito na natureza dessa estrutura. Tenho certeza de que você poderia fazer algumas melhorias importantes na memória, substituindo chaves de objeto redundantes estranhas (mesmo que a desconstrução faça o trabalho para você).Antes de ler o que vem a seguir
Agora percebo que minha ênfase não é exatamente a melhor maneira de resolver o problema e, como Benjamin Gruenbaum apontou (confira sua resposta, se já não estiver acima da minha: p), esse problema não poderia ter sido resolvido regularmente
Map
, pois teria vazado, portanto, o principal ponto forteWeakMap
é que ele não interfere na coleta de lixo, uma vez que eles não mantêm uma referência.Aqui está o código real do meu colega de trabalho (graças a ele para compartilhamento)
Fonte completa aqui , é sobre gerenciamento de ouvintes de que falei acima (você também pode dar uma olhada nas especificações )
fonte
WeakMap
funciona bem para encapsulamento e ocultação de informaçõesWeakMap
está disponível apenas para ES6 e acima. AWeakMap
é uma coleção de pares de chave e valor em que a chave deve ser um objeto. No exemplo a seguir, criamos umWeakMap
com dois itens:Usamos o
set()
método para definir uma associação entre um objeto e outro item (uma string no nosso caso). Usamos oget()
método para recuperar o item associado a um objeto. O aspecto interessante doWeakMap
s é o fato de ele conter uma referência fraca à chave dentro do mapa. Uma referência fraca significa que, se o objeto for destruído, o coletor de lixo removerá toda a entrada daWeakMap
, liberando memória.fonte
𝗠𝗲𝘁𝗮𝗱𝗮𝘁𝗮
Mapas fracos podem ser usados para armazenar metadados sobre elementos DOM sem interferir na coleta de lixo ou deixar os colegas de trabalho zangados com seu código. Por exemplo, você pode usá-los para indexar numéricos todos os elementos em uma página da web.
𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗼𝗿 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗮𝗻𝗱 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗧𝗵𝗲 𝗗𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝗰𝗲
A diferença pode parecer insignificante, além do fato de a versão fraca do mapa ser maior, no entanto, há uma grande diferença entre os dois trechos de código mostrados acima. No primeiro trecho de código, sem mapas fracos, o trecho de código armazena referências de todas as formas entre os elementos DOM. Isso evita que os elementos DOM sejam coletados como lixo.
(i * i) % len
pode parecer uma coisa esquisita que ninguém usaria, mas pense novamente: bastante código de produção possui referências DOM que saltam por todo o documento. Agora, para o segundo trecho de código, porque todas as referências aos elementos são fracas, quando você remove um nó, o navegador pode determinar que o nó não é usado (não pode ser alcançado pelo seu código) e exclua-o da memória. A razão pela qual você deve se preocupar com o uso de memória e as âncoras de memória (coisas como o primeiro trecho de código em que elementos não utilizados são mantidos na memória) é porque mais uso de memória significa mais tentativas de GC do navegador (para tentar liberar memória para evitar uma falha no navegador) significa uma experiência de navegação mais lenta e, às vezes, uma falha no navegador.Quanto a um polyfill para esses, eu recomendaria minha própria biblioteca ( encontrada aqui no github ). É uma biblioteca muito leve que simplesmente o preenche com polyfill sem nenhuma das estruturas complexas demais que você pode encontrar em outros polyfills.
~ Feliz codificação!
fonte
elements
como nulo e pronto: será GCed. & Re " Referências DOM que saltam por todo o documento ", não importa:elements
Quando o link principal se for, todas as referências circulares serão GCed. Se o seu elemento estiver mantendo referências ao elemento que não precisa, corrija o código e defina o ref como null quando terminar de usá-lo. Será GCed. Mapas fracos não são necessários .elements
para null não permitirá que o navegador faça o GC dos elementos na primeira situação de snippet. Isso ocorre porque você define propriedades customizadas nos elementos e, em seguida, esses elementos ainda podem ser obtidos e suas propriedades customizadas ainda podem ser acessadas, impedindo que qualquer um deles seja GC'ed. Pense nisso como uma corrente de anéis de metal. Quando você tem acesso a pelo menos um elo da cadeia, pode segurá-lo e impedir que toda a cadeia de itens caia no abismo.eu uso
WeakMap
para o cache de memorização sem preocupações de funções que recebem objetos imutáveis como parâmetro.Memoização é uma maneira elegante de dizer "depois de calcular o valor, armazene-o em cache para que você não precise calculá-lo novamente".
Aqui está um exemplo:
Mostrar snippet de código
Algumas coisas a serem observadas:
fonte
Eu tenho esse caso de uso baseado em recursos simples / exemplo para WeakMaps.
GERIR UMA COLEÇÃO DE USUÁRIOS
Comecei com um
User
objeto cujas propriedades incluem umfullname
,username
,age
,gender
e um método chamadoprint
que imprime um resumo legível das outras propriedades.Em seguida, adicionei um mapa chamado
users
para manter uma coleção de vários usuários digitados porusername
.A adição da coleção também exigia funções auxiliares para adicionar, obter, excluir um usuário e até uma função para imprimir todos os usuários por uma questão de integridade.
Com todo o código acima em execução, digamos NodeJS , apenas o
users
Mapa tem a referência aos Objetos do Usuário em todo o processo. Não há outra referência aos objetos de usuário individuais.Executando este código um shell NodeJS interativo, apenas como um exemplo, adiciono quatro usuários e os imprimo:
ADICIONE MAIS INFORMAÇÃO AOS USUÁRIOS SEM MODIFICAR O CÓDIGO EXISTENTE
Agora, digamos que um novo recurso seja necessário, em que os links de SMP (Social Media Platform) de cada usuário precisam ser rastreados junto com os Objetos de Usuário.
A chave aqui é também que esse recurso deve ser implementado com o mínimo de intervenção no código existente.
Isso é possível com o WeakMaps da seguinte maneira.
Eu adiciono três WeakMaps separados para Twitter, Facebook, LinkedIn.
Uma função auxiliar
getSMPWeakMap
é adicionada simplesmente para retornar o WeakMap associado ao nome SMP fornecido.Uma função para adicionar o link SMP de um usuário ao SMP WeakMap fornecido.
Uma função para imprimir apenas os usuários presentes no SMP especificado.
Agora você pode adicionar links SMP para os usuários, também com a possibilidade de cada usuário ter um link em vários SMPs.
... continuando com o exemplo anterior, adiciono links SMP aos usuários, vários links para os usuários Bill e Sarah e imprimo os links para cada SMP separadamente:
Agora diga que um usuário é excluído do
users
mapa chamandodeleteUser
. Isso remove a única referência ao objeto de usuário. Isso, por sua vez, também limpará o link SMP de qualquer / todos os SMP WeakMaps (por Garbage Collection), pois sem o Objeto do Usuário, não há como acessar qualquer link SMP.... continuando com o exemplo, excluo o usuário Bill e imprimo os links dos SMPs aos quais ele foi associado:
Não há necessidade de qualquer código adicional para excluir individualmente o link SMP separadamente e o código existente antes que esse recurso não fosse modificado.
Se houver outra maneira de adicionar esse recurso com / sem WeakMaps, fique à vontade para comentar.
fonte