Est-il possible de créer une «référence faible» en javascript?

98

Existe-t-il un moyen en javascript pour créer une "référence faible" à un autre objet? Voici la page wiki décrivant ce qu'est une référence faible. Voici un autre article qui les décrit en Java. Quelqu'un peut-il penser à un moyen d'implémenter ce comportement en javascript?

Stephen Cagle
la source
4
Des références faibles sont en cours de discussion pour ES6. Garde les yeux ouverts.
Ryan Smith
2
* Wiki / discussion sur les spécifications officielles sur wiki.ecmascript.org/doku.php?id=strawman:weak_refs , actuellement «Dernière modification: 02/02/2013 22:25» * une autre discussion sur les spécifications sur esdiscuss.org/topic/what -is-the-status-of-low-references , actuellement dernier message «Dim 3 mars 11:56:05 PST 2013»
Destiny Architect
Dans la plupart des cas, les WR sont une tentative de résoudre le problème de l' auditeur en boucle , discuté ici: [ stackoverflow.com/questions/43758217/… . Si cette question avait une bonne réponse, je ne pense pas qu'il y aurait un grand besoin de WR.
James
@supercat J'ai publié une réponse à la question de l'auditeur caduque .
James

Réponses:

39

Il n'y a pas de prise en charge de langage pour les références faibles en JavaScript. Vous pouvez rouler le vôtre en utilisant le comptage manuel des références, mais pas particulièrement en douceur. Vous ne pouvez pas créer un objet wrapper proxy, car dans JavaScript, les objets ne savent jamais quand ils sont sur le point d'être récupérés.

Ainsi, votre `` référence faible '' devient une clé (par exemple, un entier) dans une simple recherche, avec une méthode d'ajout et de suppression de référence, et lorsqu'il n'y a plus de références suivies manuellement, l'entrée peut être supprimée, laissant les recherches futures activées cette clé pour retourner null.

Ce n'est pas vraiment une référence faible, mais cela peut résoudre certains des mêmes problèmes. Cela se fait généralement dans des applications Web complexes pour éviter les fuites de mémoire des navigateurs (généralement IE, en particulier les versions plus anciennes) lorsqu'il existe une boucle de référence entre un nœud DOM ou un gestionnaire d'événements et un objet qui lui est associé, comme une fermeture. Dans ces cas, un système complet de comptage des références peut même ne pas être nécessaire.

bobince
la source
2
Je n'ai pas soigneusement examiné (ou utilisé) le code, mais es-lab a un script fournissant une émulation de base WeakMap . Aurora 6 (Mozilla) a une implémentation WeakMap non standard .
theazureshadow
2
Avec ES6, cette réponse n'est plus correcte. Voir ma réponse ci-dessous stackoverflow.com/a/28567560/745190
thelastshadow
9
C'est toujours correct, car ES6 WeakMaps ne sont pas de véritables références faibles. Les WeakMaps acceptent les objets comme des clés uniquement et les références à ces objets sont conservées faiblement. Voir stackoverflow.com/questions/32397729/…
CodeManX
J'ai écrit une classe pour émuler une carte faible et l'ai postée ici: stackoverflow.com/a/47017206/491553
Ryan Shillington
11

Mise à jour: septembre 2019

Il n'est pas encore possible d'utiliser des références faibles, mais très probablement bientôt, cela sera possible, car les WeakRefs en JavaScript sont en cours de travail. Détails ci-dessous.

Proposition

La proposition est maintenant à l' étape 3, ce qui signifie qu'elle a une spécification complète et qu'un raffinement supplémentaire nécessitera un retour d'informations de la part des implémentations et des utilisateurs.

La proposition WeakRef comprend deux nouvelles fonctionnalités majeures:

  • Création de références faibles à des objets avec la classe WeakRef
  • Exécution de finaliseurs définis par l'utilisateur après la récupération des objets, avec la classe FinalizationGroup

Cas d'utilisation

Une utilisation principale des références faibles est d'implémenter des caches ou des mappages contenant des objets volumineux, où il est souhaitable qu'un objet volumineux ne soit pas maintenu en vie uniquement parce qu'il apparaît dans un cache ou un mappage.

La finalisation est l'exécution de code à nettoyer après un objet devenu inaccessible à l'exécution du programme. Les finaliseurs définis par l'utilisateur permettent plusieurs nouveaux cas d'utilisation et peuvent aider à éviter les fuites de mémoire lors de la gestion de ressources que le garbage collector ne connaît pas.

Source et lectures complémentaires

https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references

M. Twarog
la source
1
Firefox Nightly a ajouté un support expérimental pour WeakRef. Voici un exemple d'implémentation qui l'utilise pour créer une version itérable de WeakSet: gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley
3

De vraies références faibles, non, pas encore (mais les fabricants de navigateurs se penchent sur le sujet). Mais voici une idée sur la façon de simuler des références faibles.

Vous pouvez créer un cache dans lequel vous conduisez vos objets. Lorsqu'un objet est stocké, le cache conserve une prédiction de la quantité de mémoire occupée par l'objet. Pour certains éléments, comme le stockage d'images, c'est simple à résoudre. Pour d'autres, ce serait plus difficile.

Lorsque vous avez besoin d'un objet, vous le demandez au cache. Si le cache contient l'objet, il est renvoyé. S'il n'y figure pas, l'élément est généré, stocké puis renvoyé.

Les références faibles sont simulées par le cache en supprimant des éléments, lorsque la quantité totale de mémoire prévue atteint un certain niveau. Il permettra de prédire quels éléments sont les moins utilisés en fonction de la fréquence à laquelle ils sont récupérés, pondérés par le temps écoulé depuis qu'ils ont été retirés. Un coût de «calcul» pourrait également être ajouté, si le code qui crée l'élément est passé dans le cache en guise de fermeture. Cela permettrait au cache de conserver des éléments qui sont très coûteux à construire ou à générer.

L'algorithme de suppression est essentiel, car si vous vous trompez, vous risquez de supprimer les éléments les plus populaires. Cela entraînerait des performances terribles.

Tant que le cache est le seul objet avec des références permanentes aux objets stockés, le système ci-dessus devrait fonctionner plutôt bien comme alternative aux vraies références faibles.

JL235
la source
25
La plupart de ce que vous avez dit n'est-il pas pertinent pour les références faibles?
Erik Kaplun
22
@ JL235 - l'utilisation importante des références faibles n'est pas pour les caches mais pour les gestionnaires d'événements. J'ai un objet qui, tant qu'il existe, devrait observer un autre événement - mais je ne veux pas que le fait qu'il soit dans une liste de notification constitue une référence aux fins de GC.
Malvolio
7
Les références faibles n'ont rien à voir avec la mise en cache. Une référence faible signifie que vous voulez garder une trace de quelque chose, mais s'il n'y a plus de références à l'objet suivi, vous autorisez sa suppression.
fabspro
8
Il existe clairement un cas d'utilisation pour créer un cache en utilisant des références faibles pour une expiration automatique.
Phil Freeman
5
La mise en cache est traditionnellement la principale raison des références faibles. La chose DOM du gestionnaire d'événements est seulement une chose boguée de l'explorateur IE.
axkibe
2

Utiliser un mécanisme de mise en cache pour émuler une référence faible, comme JL235 suggéré ci - dessus , est raisonnable. Si des références faibles existaient nativement, vous observeriez un comportement comme celui-ci:

this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not

Alors qu'avec un cache, vous observeriez:

this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts

En tant que détenteur d'une référence, vous ne devez faire aucune hypothèse sur le moment où elle fait référence à une valeur, ce n'est pas différent en utilisant un cache

Markus
la source
-4

EcmaScript 6 (ES Harmony) a un objet WeakMap . La prise en charge des navigateurs parmi les navigateurs modernes est plutôt bonne (les 3 dernières versions de Firefox, Chrome et même une version IE à venir le prennent en charge).

la dernière ombre
la source
29
Ce n'est pas exactement la même chose. A WeakMapne donne pas de références faibles aux objets - ce ne sont pas les valeurs qui sont des références faibles dans WeakMap, mais les clés . Le fait que des références faibles existent dans la carte n'est qu'un mécanisme de prévention des fuites de mémoire, et n'est pas observable par l'utilisateur autrement.
EyasSH
1
Vous avez raison de dire que ce sont les clés qui sont faibles, pas les valeurs. Mais tout le but de l'utilisation de références faibles est d'autoriser le garbage collection de l'objet référencé. L'OP a publié deux liens, dont le second concerne l'ajout d'un identifiant à un objet que vous ne pouvez pas étendre, et en fait, il recommande d'utiliser WeakHashMap, l'équivalent Java de WeakMap de JavaScript.
thelastshadow
12
bonne chance à l' aide WeakMap pour mettre en œuvre une référence faible depuis weakmap.get(new String('any possible key that has ever existed or ever will exist'))sera toujours être undefined. Pas utile. Vote à la baisse!
user3338098
-5

http://www.jibbering.com/faq/faq_notes/closures.html

ECMAScript utilise le garbage collection automatique. La spécification ne définit pas les détails, laissant le soin aux implémenteurs de trier, et certaines implémentations sont connues pour donner une très faible priorité à leurs opérations de garbage collection. Mais l'idée générale est que si un objet devient non référençable (en n'ayant aucune référence restante à lui laissée accessible au code en cours d'exécution), il devient disponible pour le garbage collection et sera à un moment donné ultérieurement détruit et toutes les ressources qu'il consomme libérées et retournées au système pour réutilisation.

Ce serait normalement le cas à la sortie d'un contexte d'exécution. La structure de la chaîne de portée, l'objet Activation / Variable et tous les objets créés dans le contexte d'exécution, y compris les objets de fonction, ne seraient plus accessibles et deviendraient ainsi disponibles pour le garbage collection.

Cela signifie qu'il n'y a pas de faibles, seulement ceux qui ne sont plus disponibles.

branchegabriel
la source
10
Éviter les cycles de référence n'est pas la seule raison d'utiliser des références faibles. Ils sont très pratiques pour la mise en commun / la mise en cache d'instances d'objets, etc.
pelucheux le
La définition de WeakReference n'est pas une question. Aussi d'accord avec le commentaire ci-dessus.
Yuri Yaryshev