Czy można utworzyć „słabe odniesienie” w javascript?

98

Czy istnieje sposób w javascript, aby utworzyć „słabe odniesienie” do innego obiektu? Oto strona wiki opisująca, czym jest słabe odniesienie. Oto kolejny artykuł opisujący je w Javie. Czy ktoś może wymyślić sposób na zaimplementowanie tego zachowania w javascript?

Stephen Cagle
źródło
4
Słabe odniesienia są omawiane w ES6. Miej oczy szeroko otwarte.
Ryan Smith
2
* Oficjalna specyfikacja wiki / dyskusja na wiki.ecmascript.org/doku.php?id=strawman:weak_refs , obecnie „Ostatnia modyfikacja: 2013/02/02 22:25” * inna dyskusja na temat specyfikacji na esdiscuss.org/topic/what -jest-stan-słabych-odniesień , obecnie ostatni post „Sun 3 Mar 11:56:05 PST 2013”
Destiny Architect
W większości przypadków WR są próbą rozwiązania problemu Lapsed Listener , omówionego tutaj: [ stackoverflow.com/questions/43758217/… . Gdyby na to pytanie udzielono dobrej odpowiedzi, nie sądzę, by byłyby potrzebne WR.
James
@supercat Wysłałem odpowiedź na wygasłe pytanie słuchacza .
James

Odpowiedzi:

39

W JavaScript nie ma obsługi języków dla slabych odwołań. Możesz tworzyć własne, korzystając z ręcznego liczenia referencji, ale nie jest to szczególnie płynne. Nie można utworzyć obiektu opakowującego proxy, ponieważ w JavaScript obiekty nigdy nie wiedzą, kiedy zostaną zebrane jako elementy bezużyteczne.

Tak więc Twoje „słabe odniesienie” staje się kluczem (np. Liczbą całkowitą) w prostym wyszukiwaniu, z metodą dodawania i usuwania odniesienia, a gdy nie ma już odniesień śledzonych ręcznie, wpis można usunąć, pozostawiając przyszłe wyszukiwania włączone ten klucz, aby zwrócić null.

Nie jest to tak naprawdę słaby punkt, ale może rozwiązać niektóre z tych samych problemów. Zwykle jest to wykonywane w złożonych aplikacjach internetowych, aby zapobiec wyciekowi pamięci z przeglądarek (zwykle IE, zwłaszcza starszych wersji), gdy istnieje pętla odwołań między węzłem DOM lub obsługą zdarzeń a powiązanym z nim obiektem, takim jak zamknięcie. W takich przypadkach pełny schemat liczenia referencji może nawet nie być konieczny.

bobince
źródło
2
Nie zbadałem (ani nie użyłem) dokładnie kodu, ale es-lab ma skrypt zapewniający podstawową emulację WeakMap . Aurora 6 (Mozilla) ma niestandardową implementację WeakMap .
theazureshadow
2
W ES6 ta odpowiedź nie jest już poprawna. Zobacz moją odpowiedź poniżej stackoverflow.com/a/28567560/745190
thelastshadow
9
Nadal jest poprawna, ponieważ ES6 WeakMaps nie są prawdziwymi słabymi odniesieniami. WeakMaps akceptują obiekty tylko jako klucze, a odniesienia do tych obiektów są przechowywane słabo. Zobacz stackoverflow.com/questions/32397729/…
CodeManX
Napisałem klasę, aby emulować słabą mapę i opublikowałem ją tutaj: stackoverflow.com/a/47017206/491553
Ryan Shillington
11

Aktualizacja: wrzesień 2019 r

Na razie nie można używać słabych referencji, ale najprawdopodobniej wkrótce będzie to możliwe, ponieważ WeakRefs w JavaScript to praca w toku. Szczegóły poniżej.

Wniosek

Wniosek jest teraz w etapie 3, co oznacza, że ​​został ukończony specyfikację, a dalsze udoskonalenia będą wymagały informacji zwrotnych od wdrożeń i użytkowników.

WeakRef propozycja obejmuje dwa główne nowe kawałki funkcjonalności:

  • Tworzenie słabych odniesień do obiektów z rozszerzeniem klasą WeakRef
  • Uruchamianie finalizatorów zdefiniowanych przez użytkownika po tym, jak obiekty są zbierane jako elementy bezużyteczne, z rozszerzeniem klasy FinalizationGroup

Przypadków użycia

Podstawowym zastosowaniem słabych odniesienia jest wykonanie bufory lub mapowania posiadających duże przedmioty, gdzie jest pożądane, aby duża obiekt nie jest utrzymywane przy życiu tylko dlatego, że występuje w pamięci podręcznej i mapowania.

Finalizacja to wykonanie kodu w celu oczyszczenia obiektu, który stał się niedostępny dla wykonywania programu. Finalizatory zdefiniowane przez użytkownika umożliwiają kilka nowych przypadków użycia i mogą pomóc w zapobieganiu wyciekom pamięci podczas zarządzania zasobami, o których nie wie moduł odśmiecania pamięci.

Źródło i dalsze czytanie

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

M. Twarog
źródło
1
Firefox Nightly dodał eksperymentalną obsługę WeakRef. Oto przykładowa implementacja używająca go do tworzenia iterowalnej wersji WeakSet: gist.github.com/seanlinsley/bc10378fd311d75cf6b5e80394be813d
seanlinsley
3

Prawdziwie słabe odniesienia, nie, jeszcze nie (ale twórcy przeglądarek przyglądają się temu tematowi). Ale oto pomysł, jak symulować słabe odniesienia.

Możesz zbudować pamięć podręczną, przez którą przepuszczasz swoje obiekty. Kiedy obiekt jest przechowywany, pamięć podręczna przechowuje przewidywanie, ile pamięci zajmie obiekt. W przypadku niektórych pozycji, takich jak przechowywanie obrazów, jest to proste do rozwiązania. Dla innych byłoby to trudniejsze.

Kiedy potrzebujesz obiektu, poproś o niego pamięć podręczną. Jeśli pamięć podręczna zawiera obiekt, jest on zwracany. Jeśli go tam nie ma, element jest generowany, przechowywany, a następnie zwracany.

Słabe referencje są symulowane przez elementy usuwające pamięć podręczną, gdy całkowita ilość przewidywanej pamięci osiągnie określony poziom. Przewiduje, które elementy są najmniej używane, na podstawie tego, jak często są one odzyskiwane, ważone według tego, jak dawno zostały wyjęte. Koszt „kalkulacji” można również dodać, jeśli kod, który tworzy element, jest przekazywany do pamięci podręcznej jako zamknięcie. Umożliwiłoby to przechowywanie w pamięci podręcznej przedmiotów, które są bardzo drogie w budowie lub generowaniu.

Algorytm usuwania jest kluczowy, ponieważ jeśli się pomylisz, możesz w końcu usunąć najpopularniejsze elementy. To spowodowałoby straszne wyniki.

Tak długo, jak pamięć podręczna jest jedynym obiektem z trwałymi odniesieniami do przechowywanych obiektów, powyższy system powinien działać całkiem dobrze jako alternatywa dla prawdziwych słabych odniesień.

JL235
źródło
25
Czy większość tego, co powiedziałeś, nie jest nieistotna dla słabe punkty?
Erik Kaplun,
22
@ JL235 - ważne zastosowanie słabych odwołań nie dotyczy pamięci podręcznych, ale programów obsługi zdarzeń. Mam jakiś przedmiot, który, choć istnieje, powinien obserwować inne zdarzenie - ale nie chcę, aby fakt, że znajduje się on na liście zgłoszeń, stanowił odniesienie dla celów GC.
Malvolio
7
Słabe odwołania nie mają nic wspólnego z buforowaniem. Słabe odniesienie oznacza, że ​​chcesz coś śledzić, ale jeśli nie ma pozostałych odniesień do śledzonego obiektu, pozwalasz na jego usunięcie.
fabspro
8
Oczywiście istnieje przypadek użycia tworzenia pamięci podręcznej przy użyciu słabych referencji do automatycznego wygaśnięcia.
Phil Freeman
5
Buforowanie jest tradycyjnie głównym powodem słabych odniesień. Program obsługi zdarzeń DOM jest tylko jedną z wad eksploratora IE.
axkibe,
2

Użycie mechanizmu buforowania do emulacji słabej referencji, jak sugerowano powyżej JL235 , jest rozsądne. Jeśli słabe referencje istniałyby natywnie, zaobserwowałbyś takie zachowanie:

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

Podczas gdy w przypadku pamięci podręcznej zaobserwowałbyś:

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

Jako posiadacz odniesienia nie powinieneś robić żadnych założeń co do tego, kiedy odwołuje się on do wartości, nie inaczej jest w przypadku użycia pamięci podręcznej

Markus
źródło
-4

EcmaScript 6 (ES Harmony) ma obiekt WeakMap . Obsługa przeglądarek wśród nowoczesnych przeglądarek jest całkiem dobra (obsługują ją ostatnie 3 wersje Firefoksa, Chrome, a nawet nadchodząca wersja IE).

thelastshadow
źródło
29
To nie jest dokładnie to samo. A WeakMapnie daje słabych odniesień do obiektów - to nie wartości są słabymi odniesieniami w WeakMap, ale klucze . Fakt, że w mapie istnieją słabe odwołania, jest jedynie mechanizmem zapobiegania wyciekom pamięci i nie jest obserwowalny dla użytkownika w inny sposób.
EyasSH
1
Masz rację, że to klucze są słabe, a nie wartości. Jednak celem używania słabych odwołań jest umożliwienie czyszczenia pamięci obiektu, do którego się odwołuje. OP opublikował dwa linki, z których drugi dotyczy dodawania identyfikatora do obiektu, którego nie można rozszerzyć, i faktycznie zaleca użycie WeakHashMap, odpowiednika WeakMap w Javie.
thelastshadow
12
Powodzenia przy użyciu WeakMap wdrożyć słabego odniesienia, ponieważ weakmap.get(new String('any possible key that has ever existed or ever will exist'))będzie zawsze być undefined. Nie przydatne. Głosowanie przeciw!
user3338098
-5

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

ECMAScript używa automatycznego czyszczenia pamięci. Specyfikacja nie definiuje szczegółów, pozostawiając to implementatorom do rozwiązania, a niektóre implementacje są znane z tego, że nadają bardzo niski priorytet swoim operacjom czyszczenia pamięci. Ale ogólna idea jest taka, że ​​jeśli obiekt staje się niemożliwy do odniesienia (przez brak pozostałych odwołań do niego dostępnych dla wykonywania kodu), staje się dostępny do czyszczenia pamięci i zostanie w przyszłości zniszczony, a wszelkie zasoby, które zużywa, zostaną zwolnione i zwrócone do systemu w celu ponownego wykorzystania.

Zwykle miałoby to miejsce w przypadku wyjścia z kontekstu wykonania. Struktura łańcucha zasięgu, obiekt Activation / Variable i wszelkie obiekty utworzone w kontekście wykonywania, w tym obiekty funkcyjne, nie byłyby już dostępne, a zatem stałyby się dostępne do czyszczenia pamięci.

Oznacza to, że nie ma słabych, tylko te, które nie są już dostępne.

branchgabriel
źródło
10
Unikanie cykli referencyjnych nie jest jedynym powodem, dla którego warto używać słabych referencji. Są bardzo przydatne do buforowania / buforowania instancji obiektów i tak dalej.
puszysty
Definicja WeakReference nie wchodzi w grę. Zgadzam się również z komentarzem powyżej.
Yuri Yaryshev