¿Es posible crear una "referencia débil" en javascript?

98

¿Hay alguna forma en JavaScript para crear una "referencia débil" a otro objeto? Aquí está la página wiki que describe qué es una referencia débil. Aquí hay otro artículo que los describe en Java. ¿Alguien puede pensar en una forma de implementar este comportamiento en javascript?

Stephen Cagle
fuente
4
Se están discutiendo referencias débiles para ES6. Mantén tus ojos abiertos.
Ryan Smith
2
* Wiki / discusión de especificaciones oficiales en wiki.ecmascript.org/doku.php?id=strawman:weak_refs , actualmente “Última modificación: 02/02/2013 22:25” * alguna otra discusión de especificaciones en esdiscuss.org/topic/what -is-el-estado-de-referencias-débiles , última publicación actual “Dom 3 de marzo a las 11:56:05 PST de 2013”
Destiny Architect
En la mayoría de los casos, los WR son un intento de resolver el Problema de escucha inactivo , que se analiza aquí: [ stackoverflow.com/questions/43758217/… . Si esa pregunta tuviera una buena respuesta, no creo que haya mucha necesidad de WR.
James
@supercat He publicado una respuesta a la pregunta del oyente transcurrido .
James

Respuestas:

39

No hay soporte de idioma para las referencias débiles en JavaScript. Puede rodar el suyo utilizando el recuento manual de referencias, pero no de forma especialmente fluida. No puede crear un objeto contenedor de proxy, porque en JavaScript, los objetos nunca saben cuándo están a punto de ser recolectados como basura.

Entonces, su 'referencia débil' se convierte en una clave (por ejemplo, un número entero) en una búsqueda simple, con un método de agregar referencia y eliminar referencia, y cuando ya no hay referencias rastreadas manualmente, la entrada se puede eliminar, dejando futuras búsquedas en esa clave para devolver nulo.

Esto no es realmente una referencia débil, pero puede resolver algunos de los mismos problemas. Por lo general, se realiza en aplicaciones web complejas para evitar la pérdida de memoria de los navegadores (generalmente IE, especialmente versiones anteriores) cuando hay un bucle de referencia entre un Nodo DOM o controlador de eventos y un objeto asociado con él, como un cierre. En estos casos, es posible que ni siquiera sea necesario un sistema completo de recuento de referencias.

bobince
fuente
2
No he examinado (o usado) cuidadosamente el código, pero es-lab tiene un script que proporciona una emulación básica de WeakMap . Aurora 6 (Mozilla) tiene una implementación WeakMap no estándar .
theazureshadow
2
Con ES6 esta respuesta ya no es correcta. Vea mi respuesta a continuación stackoverflow.com/a/28567560/745190
thelastshadow
9
Todavía es correcto, porque ES6 WeakMaps no son verdaderas referencias débiles. WeakMaps acepta objetos solo como claves, y las referencias a estos objetos se mantienen débilmente. Ver stackoverflow.com/questions/32397729/…
CodeManX
Escribí una clase para emular un mapa débil y la publiqué aquí: stackoverflow.com/a/47017206/491553
Ryan Shillington
11

Actualización: septiembre de 2019

No es posible usar referencias débiles todavía, pero lo más probable es que pronto sea posible, ya que WeakRefs en JavaScript están en proceso. Detalles abajo.

Propuesta

La propuesta está ahora en la Etapa 3, lo que significa que tiene una especificación completa y que un mayor refinamiento requerirá comentarios de las implementaciones y los usuarios.

La propuesta de WeakRef abarca dos nuevas funciones importantes:

  • Creando referencias débiles a objetos con la clase WeakRef
  • Ejecutar finalizadores definidos por el usuario después de que los objetos se recolectan como basura, con la clase FinalizationGroup

Casos de uso

Un uso principal de las referencias débiles es implementar cachés o mapeos que contienen objetos grandes, donde se desea que un objeto grande no se mantenga vivo únicamente porque aparece en un caché o mapeo.

La finalización es la ejecución de código para limpiar después de un objeto que se ha vuelto inalcanzable para la ejecución del programa. Los finalizadores definidos por el usuario permiten varios casos de uso nuevos y pueden ayudar a prevenir pérdidas de memoria al administrar recursos que el recolector de basura no conoce.

Fuente y lectura adicional

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

M. Twarog
fuente
1
Firefox Nightly ha agregado soporte experimental para WeakRef. Aquí hay un ejemplo de implementación que lo usa para crear una versión iterable de WeakSet: gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley
3

Verdaderas referencias débiles, no, todavía no (pero los fabricantes de navegadores están analizando el tema). Pero aquí hay una idea sobre cómo simular referencias débiles.

Podría crear un caché a través del cual conducir sus objetos. Cuando se almacena un objeto, la caché mantiene una predicción de cuánta memoria ocupará el objeto. Para algunos elementos, como el almacenamiento de imágenes, esto es sencillo de resolver. Para otros, esto sería más difícil.

Cuando necesite un objeto, solicítelo al caché. Si la caché tiene el objeto, se devuelve. Si no está allí, el elemento se genera, se almacena y luego se devuelve.

Las referencias débiles se simulan mediante la eliminación de elementos de la memoria caché, cuando la cantidad total de memoria prevista alcanza un cierto nivel. Predecirá qué elementos se utilizan menos en función de la frecuencia con la que se recuperan, ponderado por cuánto tiempo se retiraron. También se podría agregar un costo de 'cálculo', si el código que crea el artículo se pasa a la caché como un cierre. Esto permitiría que la caché guarde elementos que son muy costosos de construir o generar.

El algoritmo de eliminación es clave, porque si se equivoca, podría terminar eliminando los elementos más populares. Esto causaría un rendimiento terrible.

Siempre que el caché sea el único objeto con referencias permanentes a los objetos almacenados, entonces el sistema anterior debería funcionar bastante bien como una alternativa a las verdaderas referencias débiles.

JL235
fuente
25
¿No es la mayor parte de lo que dijiste irrelevante para las referencias débiles?
Erik Kaplun
22
@ JL235: el uso importante de referencias débiles no es para cachés sino para controladores de eventos. Tengo algún objeto que, mientras existe, debería observar algún otro evento, pero no quiero que el hecho de que esté en una lista de notificaciones constituya una referencia para los propósitos de GC.
Malvolio
7
Las referencias débiles no tienen nada que ver con el almacenamiento en caché. Una referencia débil significa que desea realizar un seguimiento de algo, pero si no quedan referencias al objeto que se está rastreando, permite que se elimine.
fabspro
8
Claramente, existe un caso de uso para construir un caché usando referencias débiles para el vencimiento automático.
Phil Freeman
5
El almacenamiento en caché es tradicionalmente una de las principales razones de las referencias débiles. El controlador de eventos DOM es solo algo con errores del explorador de IE.
axkibe
2

Es razonable usar un mecanismo de almacenamiento en caché para emular una referencia débil, como sugirió JL235 anteriormente . Si las referencias débiles existieran de forma nativa, observaría un comportamiento como este:

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

Mientras que con un caché observaría:

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

Como titular de una referencia, no debe hacer suposiciones sobre cuándo se refiere a un valor, esto no es diferente al usar un caché

Markus
fuente
-4

EcmaScript 6 (ES Harmony) tiene un objeto WeakMap . El soporte del navegador entre los navegadores modernos es bastante bueno (las últimas 3 versiones de Firefox, Chrome e incluso una próxima versión de IE lo admiten).

thelastshadow
fuente
29
Esto no es exactamente lo mismo. A WeakMapno da referencias débiles a objetos; no son los valores los que son referencias débiles en WeakMap, sino las claves . El hecho de que existan referencias débiles en el mapa es solo un mecanismo de prevención de fugas de memoria y no es observable para el usuario de otra manera.
EyasSH
1
Tiene razón en que son las claves las que son débiles, no los valores. Pero todo el propósito de usar referencias débiles es permitir la recolección de basura del objeto referenciado. El OP publicó dos enlaces, el segundo de los cuales trata sobre agregar una identificación a un objeto que no puede extender y, de hecho, recomienda usar WeakHashMap, el equivalente en Java del WeakMap de JavaScript.
thelastshadow
12
buena suerte usando WeakMap para implementar una referencia débil ya weakmap.get(new String('any possible key that has ever existed or ever will exist'))que siempre lo será undefined. No es útil. ¡Votar en contra!
user3338098
-5

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

ECMAScript utiliza la recolección automática de basura. La especificación no define los detalles, dejando que los implementadores lo resuelvan, y se sabe que algunas implementaciones dan una prioridad muy baja a sus operaciones de recolección de basura. Pero la idea general es que si un objeto se vuelve irreferible (al no tener referencias restantes a él accesibles para ejecutar el código), estará disponible para la recolección de basura y en algún momento futuro será destruido y cualquier recurso que esté consumiendo será liberado y devuelto. al sistema para su reutilización.

Este sería normalmente el caso al salir de un contexto de ejecución. La estructura de la cadena de alcance, el objeto Activación / Variable y cualquier objeto creado dentro del contexto de ejecución, incluidos los objetos de función, ya no serán accesibles y, por lo tanto, estarán disponibles para la recolección de basura.

Lo que significa que no hay débiles, solo los que ya no están disponibles.

Branchgabriel
fuente
10
Evitar los ciclos de referencia no es la única razón para utilizar referencias débiles. Son muy útiles para la agrupación / almacenamiento en caché de instancias de objetos, etc.
esponjoso
La definición de WeakReference no es una cuestión. También de acuerdo con el comentario anterior.
Yuri Yaryshev