Quelles sont les utilisations réelles d'ES6 WeakMap?

397

Quelles sont les utilisations réelles de la WeakMapstructure de données introduite dans ECMAScript 6?

Étant donné qu'une clé d'une carte faible crée une référence forte à sa valeur correspondante, garantissant qu'une valeur qui a été insérée dans une carte faible ne disparaîtra jamais tant que sa clé est toujours vivante, elle ne peut pas être utilisée pour les tableaux de mémos, caches ou toute autre chose pour laquelle vous utiliseriez normalement des références faibles, des cartes avec des valeurs faibles, etc. pour.

Il me semble que ceci:

weakmap.set(key, value);

... est juste une façon détournée de dire ceci:

key.value = value;

Quels cas concrets me manquent?

valderman
la source
35
Cas d'utilisation réel: stockez des données personnalisées pour les nœuds DOM.
Felix Kling le
Tous les cas d'utilisation que vous mentionnez pour les références faibles sont également très importants. Ils sont juste beaucoup plus difficiles à ajouter à la langue car ils introduisent le non-déterminisme. Mark Miller et d'autres ont fait beaucoup de travail sur les références faibles et je pense qu'ils finiront par arriver. Finalement
Benjamin Gruenbaum
2
WeakMaps peut être utilisé pour détecter les fuites de mémoire: stevehanov.ca/blog/?id=148
theWebalyst

Réponses:

513

Fondamentalement

WeakMaps fournit un moyen d'étendre des objets de l'extérieur sans interférer avec la récupération de place. Chaque fois que vous souhaitez étendre un objet mais ne le pouvez pas car il est scellé - ou à partir d'une source externe - un WeakMap peut être appliqué.

Un WeakMap est une carte (dictionnaire) où les clés sont faibles - c'est-à-dire, si toutes les références à la clé sont perdues et qu'il n'y a plus de références à la valeur - la valeur peut être récupérée. Voyons cela d'abord à travers des exemples, puis expliquons-le un peu et terminons enfin avec une utilisation réelle.

Disons que j'utilise une API qui me donne un certain objet:

var obj = getObjectFromLibrary();

Maintenant, j'ai une méthode qui utilise l'objet:

function useObj(obj){
   doSomethingWith(obj);
}

Je veux garder une trace du nombre de fois que la méthode a été appelée avec un certain objet et signaler si elle se produit plus de N fois. Naïvement, on pourrait penser à utiliser une carte:

var map = new Map(); // maps can have object keys
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

Cela fonctionne, mais il y a une fuite de mémoire - nous gardons maintenant une trace de chaque objet de bibliothèque transmis à la fonction qui empêche les objets de bibliothèque d'être récupérés. Au lieu de cela - nous pouvons utiliser un WeakMap:

var map = new WeakMap(); // create a weak map
function useObj(obj){
    doSomethingWith(obj);
    var called = map.get(obj) || 0;
    called++; // called one more time
    if(called > 10) report(); // Report called more than 10 times
    map.set(obj, called);
}

Et la fuite de mémoire a disparu.

Cas d'utilisation

Certains cas d'utilisation qui autrement provoqueraient une fuite de mémoire et sont activés par WeakMaps incluent:

  • Conserver des données privées sur un objet spécifique et ne leur donner accès qu'aux personnes ayant une référence à la carte. Une approche plus ad hoc est à venir avec la proposition de symboles privés, mais c'est dans longtemps.
  • Conserver les données sur les objets de bibliothèque sans les modifier ni entraîner de surcharge.
  • Conserver des données sur un petit ensemble d'objets où de nombreux objets du type existent pour ne pas générer de problèmes avec les classes cachées utilisées par les moteurs JS pour les objets du même type.
  • Conserver les données sur les objets hôtes comme les nœuds DOM dans le navigateur.
  • Ajout d'une capacité à un objet de l'extérieur (comme l'exemple d'émetteur d'événement dans l'autre réponse).

Regardons une utilisation réelle

Il peut être utilisé pour étendre un objet de l'extérieur. Donnons un exemple pratique (adapté, en quelque sorte réel - pour faire un point) du monde réel de Node.js.

Disons que vous êtes les Node.js et vous avez des Promiseobjets - maintenant vous voulez garder une trace de toutes les promesses actuellement rejetées - cependant, vous ne pas voulez les empêcher d'être des déchets collectés dans le cas où aucune référence existent pour eux.

Maintenant, vous ne voulez pas ajouter de propriétés aux objets natifs pour des raisons évidentes - vous êtes donc bloqué. Si vous gardez des références aux promesses, vous causez une fuite de mémoire car aucune récupération de place ne peut se produire. Si vous ne conservez pas de références, vous ne pouvez pas enregistrer d'informations supplémentaires sur les promesses individuelles. Tout schéma impliquant la sauvegarde de l'ID d'une promesse signifie que vous avez besoin d'une référence à celle-ci.

Entrez WeakMaps

WeakMaps signifie que les touches sont faibles. Il n'y a aucun moyen d'énumérer une carte faible ou d'obtenir toutes ses valeurs. Dans une carte faible, vous pouvez stocker les données en fonction d'une clé et lorsque la clé est récupérée, les valeurs font de même.

Cela signifie que, étant donné une promesse, vous pouvez stocker l'état à ce sujet - et cet objet peut toujours être récupéré. Plus tard, si vous obtenez une référence à un objet, vous pouvez vérifier si vous avez un état le concernant et le signaler.

Cela a été utilisé pour mettre en œuvre des crochets de rejet non gérés par Petka Antonov comme ceci :

process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

Nous conservons des informations sur les promesses sur une carte et pouvons savoir quand une promesse rejetée a été traitée.

Benjamin Gruenbaum
la source
8
salut! Pourriez-vous me dire quelle partie de l'exemple de code provoque une fuite de mémoire?
ltamajs
15
@ ltamajs4 bien sûr, dans l' useObjexemple utilisant un Mapet non un WeakMapnous utilisons l'objet passé comme clé de carte. L'objet n'est jamais supprimé de la carte (car nous ne saurions pas quand le faire), il y a donc toujours une référence et il ne peut jamais être récupéré. Dans l'exemple WeakMap dès que toutes les autres références à l'objet ont disparu - l'objet peut être effacé du WeakMap. Si vous n'êtes toujours pas sûr de ce que je veux dire, faites-le moi savoir
Benjamin Gruenbaum
@Benjamin, Nous devons faire la distinction entre le besoin d'un cache sensible à la mémoire et le besoin d'un tuple data_object. Ne confondez pas ces deux exigences distinctes. Votre calledexemple est mieux écrit en utilisant jsfiddle.net/f2efbm7z et il ne démontre pas l'utilisation d'une carte faible. En fait, il peut être mieux écrit de 6 façons au total , que je vais énumérer ci-dessous.
Pacerier
Fondamentalement, l'objectif d'une carte faible est un cache sensible à la mémoire. Bien qu'il puisse être utilisé pour étendre des objets de l'extérieur, c'est un piratage moche et indécent et ce n'est certainement pas son objectif .
Pacerier
1
Si vous souhaitez conserver le lien entre une promesse et le nombre de fois où elle a été traitée / rejetée, utilisez 1) symbole; p[key_symbol] = data. ou 2) une dénomination unique; p.__key = data. ou 3) portée privée; (()=>{let data; p.Key = _=>data=_;})(). ou 4) proxy avec 1 ou 2 ou 3. ou 5) remplacer / étendre la classe Promise par 1 ou 2 ou 3. ou 6) remplacer / étendre la classe Promise avec un tuple de membres nécessaires. - Dans tous les cas, une carte faible n'est pas nécessaire, sauf si vous avez besoin d'un cache sensible à la mémoire.
Pacerier
48

Cette réponse semble biaisée et inutilisable dans un scénario réel. Veuillez le lire tel quel et ne le considérez pas comme une option réelle pour autre chose que l'expérimentation

Un cas d'utilisation pourrait être de l'utiliser comme dictionnaire pour les auditeurs, j'ai un collègue qui l'a fait. C'est très utile car tout auditeur est directement ciblé sur cette façon de faire les choses. Au revoir listener.on.

Mais d'un point de vue plus abstrait, WeakMapest particulièrement puissant pour dématérialiser l'accès à pratiquement tout, vous n'avez pas besoin d'un espace de noms pour isoler ses membres car il est déjà impliqué par la nature de cette structure. Je suis presque sûr que vous pourriez apporter des améliorations majeures à la mémoire en remplaçant les clés d'objet redondantes maladroites (même si la déconstruction fait le travail pour vous).


Avant de lire la suite

Je me rends compte maintenant que mon accent n'est pas exactement la meilleure façon de résoudre le problème et souligné Benjamin Gruenbaum (consultez sa réponse, si elle n'est pas déjà au-dessus de la mienne: p), ce problème n'aurait pas pu être résolu avec un habitué Map, car il aurait fui, donc la principale force de WeakMapest qu'il n'interfère pas avec la collecte des ordures étant donné qu'ils ne gardent pas de référence.


Voici le code actuel de mon collègue (merci à lui pour le partage)

La source complète ici , c'est la gestion des auditeurs dont j'ai parlé ci-dessus (vous pouvez également jeter un œil aux spécifications )

var listenableMap = new WeakMap();


export function getListenable (object) {
    if (!listenableMap.has(object)) {
        listenableMap.set(object, {});
    }

    return listenableMap.get(object);
}


export function getListeners (object, identifier) {
    var listenable = getListenable(object);
    listenable[identifier] = listenable[identifier] || [];

    return listenable[identifier];
}


export function on (object, identifier, listener) {
    var listeners = getListeners(object, identifier);

    listeners.push(listener);
}


export function removeListener (object, identifier, listener) {
    var listeners = getListeners(object, identifier);

    var index = listeners.indexOf(listener);
    if(index !== -1) {
        listeners.splice(index, 1);
    }
}


export function emit (object, identifier, ...args) {
    var listeners = getListeners(object, identifier);

    for (var listener of listeners) {
        listener.apply(object, args);
    }
}
axelduch
la source
2
Je ne comprends pas très bien comment vous utiliseriez cela. Cela entraînerait l'effondrement de l'observable ainsi que les événements qui lui sont liés lorsqu'ils ne seraient plus référencés. Le problème que j'ai tendance à avoir, c'est quand l'Observateur n'est plus référencé. Je pense que la solution ici n'a résolu que la moitié du problème. Je ne pense pas que vous puissiez résoudre le problème des observateurs avec WeakMap car il n'est pas itérable.
jgmjgm
1
Les écouteurs d'événements à double tampon peuvent être rapides dans d'autres langues, mais dans ce cas, ils sont simplement ésotériques et lents. C'est mes trois cents.
Jack Giffin
@axelduch, Wow, ce mythe de la gestion de l'auditeur a été colporté jusqu'à la communauté Javascript, gagnant 40 votes positifs! Pour comprendre pourquoi cette réponse est complètement fausse , voir les commentaires sous stackoverflow.com/a/156618/632951
Pacerier
1
@Pacerier a mis à jour la réponse, merci pour les commentaires
axelduch
1
@axelduch, oui, il y a aussi une référence à partir de là.
Pacerier
18

WeakMap fonctionne bien pour l'encapsulation et la dissimulation d'informations

WeakMapest uniquement disponible pour ES6 et supérieur. A WeakMapest une collection de paires clé et valeur où la clé doit être un objet. Dans l'exemple suivant, nous créons un WeakMapavec deux éléments:

var map = new WeakMap();
var pavloHero = {first: "Pavlo", last: "Hero"};
var gabrielFranco = {first: "Gabriel", last: "Franco"};
map.set(pavloHero, "This is Hero");
map.set(gabrielFranco, "This is Franco");
console.log(map.get(pavloHero));//This is Hero

Nous avons utilisé la set()méthode pour définir une association entre un objet et un autre élément (une chaîne dans notre cas). Nous avons utilisé la get()méthode pour récupérer l'élément associé à un objet. L'aspect intéressant du WeakMaps est le fait qu'il contient une faible référence à la clé à l'intérieur de la carte. Une référence faible signifie que si l'objet est détruit, le garbage collector supprimera l'entrée entière de la WeakMap, libérant ainsi de la mémoire.

var TheatreSeats = (function() {
  var priv = new WeakMap();
  var _ = function(instance) {
    return priv.get(instance);
  };

  return (function() {
      function TheatreSeatsConstructor() {
        var privateMembers = {
          seats: []
        };
        priv.set(this, privateMembers);
        this.maxSize = 10;
      }
      TheatreSeatsConstructor.prototype.placePerson = function(person) {
        _(this).seats.push(person);
      };
      TheatreSeatsConstructor.prototype.countOccupiedSeats = function() {
        return _(this).seats.length;
      };
      TheatreSeatsConstructor.prototype.isSoldOut = function() {
        return _(this).seats.length >= this.maxSize;
      };
      TheatreSeatsConstructor.prototype.countFreeSeats = function() {
        return this.maxSize - _(this).seats.length;
      };
      return TheatreSeatsConstructor;
    }());
})()
Michael Horojanski
la source
4
Re "faiblesse de la carte fonctionne bien pour l'encapsulation et la dissimulation d'informations". Ce n'est pas parce que vous le pouvez que vous le devriez. Javascript a des façons par défaut d'encapsuler et de cacher des informations avant même que la carte faible ne soit inventée. À l'heure actuelle, il existe littéralement 6 façons de le faire . Utiliser une carte faible pour effectuer l'encapsulation est un vilain visage.
Pacerier
12

𝗠𝗲𝘁𝗮𝗱𝗮𝘁𝗮

Les cartes faibles peuvent être utilisées pour stocker des métadonnées sur les éléments DOM sans interférer avec la récupération de place ou rendre vos collègues fous de votre code. Par exemple, vous pouvez les utiliser pour indexer numériquement tous les éléments d'une page Web.

𝗪𝗶𝘁𝗵𝗼𝘂𝘁 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗼𝗿 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:

var elements = document.getElementsByTagName('*'),
  i = -1, len = elements.length;

while (++i !== len) {
  // Production code written this poorly makes me want to cry:
  elements[i].lookupindex = i;
  elements[i].elementref = [];
  elements[i].elementref.push( elements[(i * i) % len] );
}

// Then, you can access the lookupindex's
// For those of you new to javascirpt, I hope the comments below help explain 
// how the ternary operator (?:) works like an inline if-statement
document.write(document.body.lookupindex + '<br />' + (
    (document.body.elementref.indexOf(document.currentScript) !== -1)
    ? // if(document.body.elementref.indexOf(document.currentScript) !== -1){
    "true"
    : // } else {
    "false"
  )   // }
);

𝗨𝘀𝗶𝗻𝗴 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗮𝗻𝗱 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:

var DOMref = new WeakMap(),
  __DOMref_value = Array,
  __DOMref_lookupindex = 0,
  __DOMref_otherelement = 1,
  elements = document.getElementsByTagName('*'),
  i = -1, len = elements.length, cur;

while (++i !== len) {
  // Production code written this greatly makes me want to 😊:
  cur = DOMref.get(elements[i]);
  if (cur === undefined)
    DOMref.set(elements[i], cur = new __DOMref_value)

  cur[__DOMref_lookupindex] = i;
  cur[__DOMref_otherelement] = new WeakSet();
  cur[__DOMref_otherelement].add( elements[(i * i) % len] );
}

// Then, you can access the lookupindex's
cur = DOMref.get(document.body)
document.write(cur[__DOMref_lookupindex] + '<br />' + (
    cur[__DOMref_otherelement].has(document.currentScript)
    ? // if(cur[__DOMref_otherelement].has(document.currentScript)){
    "true"
    : // } else {
    "false"
  )   // }
);

𝗧𝗵𝗲 𝗗𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝗰𝗲

La différence peut sembler négligeable, à part le fait que la version de carte faible est plus longue, mais il existe une différence majeure entre les deux morceaux de code illustrés ci-dessus. Dans le premier extrait de code, sans cartes faibles, le morceau de code stocke les références dans tous les sens entre les éléments DOM. Cela empêche les éléments DOM d'être récupérés.(i * i) % lenpeut sembler bizarre que personne n'utiliserait, mais détrompez-vous: beaucoup de code de production a des références DOM qui rebondissent sur tout le document. Maintenant, pour le deuxième morceau de code, car toutes les références aux éléments sont faibles, lorsque vous supprimez un nœud, le navigateur est en mesure de déterminer que le nœud n'est pas utilisé (impossible à atteindre par votre code), et supprimez-le donc de la mémoire. La raison pour laquelle vous devriez vous préoccuper de l'utilisation de la mémoire et des ancres de mémoire (des choses comme le premier extrait de code où les éléments inutilisés sont conservés en mémoire) est parce que plus d'utilisation de la mémoire signifie plus de tentatives de GC du navigateur (pour essayer de libérer de la mémoire pour éviter un crash du navigateur) signifie une expérience de navigation plus lente et parfois un crash du navigateur.

Quant à un polyfill pour ceux-ci, je recommanderais ma propre bibliothèque ( trouvée ici @ github ). Il s'agit d'une bibliothèque très légère qui la remplira simplement sans aucun des cadres trop complexes que vous pourriez trouver dans d'autres polyfills.

~ Bon codage!

Jack Giffin
la source
1
Merci pour l'explication claire. Un exemple vaut plus que n'importe quel mot.
newguy
@lolzery, Re " Cela empêche les éléments DOM d'être récupérés ", tout ce dont vous avez besoin est de mettre elementsà null et vous avez terminé: Ce sera GCed. & Re "Les références DOM qui rebondissent sur tout le document ", peu importe: une fois le lien principal elementsdisparu, toutes les références circulaires seront GCées. Si votre élément contient des références à un élément dont il n'a pas besoin, corrigez le code et définissez la référence sur null lorsque vous avez fini de l'utiliser. Ce sera GCed. Pas besoin de cartes faibles .
Pacerier
2
@Pacerier vous remercie pour vos commentaires enthousiastes, mais la définition elementsde null ne permettra pas au navigateur de GC les éléments dans la première situation d'extrait. Cela est dû au fait que vous définissez des propriétés personnalisées sur les éléments, puis ces éléments peuvent toujours être obtenus, et leurs propriétés personnalisées sont toujours accessibles, empêchant ainsi l'un d'eux d'être GC'ed. Pensez-y comme une chaîne d'anneaux métalliques. Solongas vous avez accès à au moins un maillon de la chaîne, vous pouvez vous accrocher à ce maillon de la chaîne, et ainsi empêcher toute la chaîne d'objets de tomber dans l'abîme.
Jack Giffin
1
code de production avec dunder nommé vars me fait vomir
Barbu Barbu
10

j'utilise WeakMap pour le cache de mémorisation sans souci des fonctions qui prennent en paramètres des objets immuables.

La mémorisation est une façon élégante de dire "après avoir calculé la valeur, mettez-la en cache pour ne pas avoir à la recalculer".

Voici un exemple:

Quelques points à noter:

  • Les objets Immutable.js renvoient de nouveaux objets (avec un nouveau pointeur) lorsque vous les modifiez, donc les utiliser comme clés dans un WeakMap garantit la même valeur calculée.
  • Le WeakMap est idéal pour les mémos car une fois que l'objet (utilisé comme clé) est récupéré, la valeur calculée sur le WeakMap fait de même.
Rico Kahler
la source
1
Il s'agit d'une utilisation valide de la carte faible tant que le cache de mémorisation est censé être sensible à la mémoire et non persistant tout au long de la vie de l'objet / fonction. Si le «cache de mémorisation» est censé être persistant tout au long de la vie de l'objet / fonction, alors la carte faible est le mauvais choix: utilisez plutôt l' une des 6 techniques d'encapsulation javascript par défaut .
Pacerier
3

J'ai ce cas d'utilisation / exemple simple basé sur des fonctionnalités pour WeakMaps.

GÉRER UNE COLLECTION D'UTILISATEURS

J'ai commencé avec un Userobjet dont les propriétés comprennent un fullname, username, age, genderet une méthode appelée printqui imprime un résumé lisible par l' homme des autres propriétés.

/**
Basic User Object with common properties.
*/
function User(username, fullname, age, gender) {
    this.username = username;
    this.fullname = fullname;
    this.age = age;
    this.gender = gender;
    this.print = () => console.log(`${this.fullname} is a ${age} year old ${gender}`);
}

J'ai ensuite ajouté une carte appelée userspour conserver une collection de plusieurs utilisateurs qui sont saisis par username.

/**
Collection of Users, keyed by username.
*/
var users = new Map();

L'ajout de la collection a également nécessité des fonctions d'aide pour ajouter, obtenir, supprimer un utilisateur et même une fonction pour imprimer tous les utilisateurs par souci d'exhaustivité.

/**
Creates an User Object and adds it to the users Collection.
*/
var addUser = (username, fullname, age, gender) => {
    let an_user = new User(username, fullname, age, gender);
    users.set(username, an_user);
}

/**
Returns an User Object associated with the given username in the Collection.
*/
var getUser = (username) => {
    return users.get(username);
}

/**
Deletes an User Object associated with the given username in the Collection.
*/
var deleteUser = (username) => {
    users.delete(username);
}

/**
Prints summary of all the User Objects in the Collection.
*/
var printUsers = () => {
    users.forEach((user) => {
        user.print();
    });
}

Avec tout le code ci-dessus exécuté, par exemple NodeJS , seule la userscarte a la référence aux objets utilisateur dans l'ensemble du processus. Il n'y a aucune autre référence aux objets utilisateur individuels.

Exécuter ce code un shell NodeJS interactif, tout comme un exemple, j'ajoute quatre utilisateurs et les imprime: Ajout et impression d'utilisateurs

AJOUTER PLUS D'INFO AUX UTILISATEURS SANS MODIFIER LE CODE EXISTANT

Supposons maintenant qu'une nouvelle fonctionnalité soit requise dans laquelle les liens de chaque utilisateur de la plateforme de médias sociaux (SMP) doivent être suivis avec les objets utilisateur.

La clé ici est également que cette fonctionnalité doit être implémentée avec une intervention minimale sur le code existant.

Ceci est possible avec WeakMaps de la manière suivante.

J'ajoute trois WeakMaps distincts pour Twitter, Facebook, LinkedIn.

/*
WeakMaps for Social Media Platforms (SMPs).
Could be replaced by a single Map which can grow
dynamically based on different SMP names . . . anyway...
*/
var sm_platform_twitter = new WeakMap();
var sm_platform_facebook = new WeakMap();
var sm_platform_linkedin = new WeakMap();

Une fonction d'assistance getSMPWeakMapest ajoutée simplement pour renvoyer le WeakMap associé au nom SMP donné.

/**
Returns the WeakMap for the given SMP.
*/
var getSMPWeakMap = (sm_platform) => {
    if(sm_platform == "Twitter") {
        return sm_platform_twitter;
    }
    else if(sm_platform == "Facebook") {
        return sm_platform_facebook;
    }
    else if(sm_platform == "LinkedIn") {
        return sm_platform_linkedin;
    }
    return undefined;
}

Une fonction pour ajouter un lien SMP d'utilisateurs au SMP WeakMap donné.

/**
Adds a SMP link associated with a given User. The User must be already added to the Collection.
*/
var addUserSocialMediaLink = (username, sm_platform, sm_link) => {
    let user = getUser(username);
    let sm_platform_weakmap = getSMPWeakMap(sm_platform);
    if(user && sm_platform_weakmap) {
        sm_platform_weakmap.set(user, sm_link);
    }
}

Une fonction pour imprimer uniquement les utilisateurs présents sur le SMP donné.

/**
Prints the User's fullname and corresponding SMP link of only those Users which are on the given SMP.
*/
var printSMPUsers = (sm_platform) => {
    let sm_platform_weakmap = getSMPWeakMap(sm_platform);
    console.log(`Users of ${sm_platform}:`)
    users.forEach((user)=>{
        if(sm_platform_weakmap.has(user)) {
            console.log(`\t${user.fullname} : ${sm_platform_weakmap.get(user)}`)
        }
    });
}

Vous pouvez maintenant ajouter des liens SMP pour les utilisateurs, également avec la possibilité pour chaque utilisateur d'avoir un lien sur plusieurs SMP.

... en continuant avec l'exemple précédent, j'ajoute des liens SMP aux utilisateurs, plusieurs liens pour les utilisateurs Bill et Sarah, puis j'imprime les liens pour chaque SMP séparément: Ajouter des liens SMP aux utilisateurs et les afficher

Supposons maintenant qu'un utilisateur soit supprimé de la userscarte en appelantdeleteUser . Cela supprime la seule référence à l'objet utilisateur. À son tour, cela effacera également le lien SMP de tout ou partie des WeakMaps SMP (par Garbage Collection) car sans l'objet utilisateur, il n'y a aucun moyen d'accéder à l'un de ses liens SMP.

... en poursuivant l'exemple, je supprime l'utilisateur Bill , puis j'imprime les liens des SMP auxquels il était associé:

La suppression de l'utilisateur Bill de la carte supprime également les liens SMP

Aucun code supplémentaire n'est requis pour supprimer individuellement le lien SMP séparément et le code existant avant que cette fonctionnalité n'ait été modifiée de toute façon.

S'il existe un autre moyen d'ajouter cette fonctionnalité avec / sans WeakMaps, n'hésitez pas à commenter.

électrocrate
la source
_____nice______
Aleks