Jakie są faktyczne zastosowania WeakMap
struktury danych wprowadzonej w ECMAScript 6?
Ponieważ klucz słabej mapy tworzy silne odniesienie do odpowiadającej jej wartości, dlatego wartość, która została wstawiona do słabej mapy, nigdy nie zniknie, dopóki klucz będzie żył, dlatego nie można jej używać w tabelach notatek, pamięci podręczne lub cokolwiek innego, do czego normalnie używasz słabych referencji, map o słabych wartościach itp.
Wydaje mi się, że to:
weakmap.set(key, value);
... to tylko ogólny sposób na powiedzenie tego:
key.value = value;
Jakich konkretnych przypadków użycia brakuje mi?
javascript
ecmascript-6
weakmap
valderman
źródło
źródło
WeakMap
S może być stosowany do wykrywania wycieków pamięci: stevehanov.ca/blog/?id=148Odpowiedzi:
Zasadniczo
WeakMaps umożliwiają rozszerzenie obiektów z zewnątrz bez ingerencji w wyrzucanie elementów bezużytecznych. Kiedykolwiek chcesz rozszerzyć obiekt, ale nie możesz, ponieważ jest on zapieczętowany - lub z zewnętrznego źródła - można zastosować WeakMap.
WeakMap to mapa (słownik), w której klucze są słabe - to znaczy, jeśli wszystkie odniesienia do klucza zostaną utracone i nie będzie już żadnych odwołań do wartości - wartość można wyrzucić. Pokażmy to najpierw za pomocą przykładów, następnie wyjaśnijmy to trochę i na koniec zakończmy prawdziwym użyciem.
Powiedzmy, że używam interfejsu API, który daje mi określony obiekt:
Teraz mam metodę, która używa obiektu:
Chcę śledzić, ile razy metoda została wywołana z określonym obiektem i zgłosić, czy zdarzy się to więcej niż N razy. Naiwnie można by pomyśleć o użyciu mapy:
Działa to, ale ma przeciek pamięci - śledzimy teraz każdy pojedynczy obiekt biblioteki przekazywany do funkcji, która chroni obiekty biblioteki przed zbieraniem śmieci. Zamiast tego - możemy użyć
WeakMap
:A przeciek pamięci zniknął.
Przypadków użycia
Niektóre przypadki użycia, które w przeciwnym razie spowodowałyby wyciek pamięci i są włączone przez
WeakMap
s obejmują:Spójrzmy na prawdziwe zastosowanie
Można go użyć do przedłużenia obiektu z zewnątrz. Podajmy praktyczny (dostosowany, w pewnym sensie prawdziwy - żeby podkreślić) przykład z prawdziwego świata Node.js.
Załóżmy, że jesteś Node.js i masz
Promise
obiekty - teraz chcesz śledzić wszystkie obecnie odrzucone obietnice - jednak nie chcesz, aby nie były one usuwane w przypadku, gdy nie ma żadnych odwołań do nich.Teraz nie chcesz dodawać właściwości do obiektów rodzimych z oczywistych powodów - więc utkniesz. Jeśli zachowasz odniesienia do obietnic, spowodujesz wyciek pamięci, ponieważ nie będzie możliwe wyrzucanie elementów bezużytecznych. Jeśli nie przechowujesz referencji, nie możesz zapisać dodatkowych informacji o poszczególnych obietnicach. Każdy schemat, który wymaga zapisania identyfikatora obietnicy z natury oznacza, że potrzebujesz odniesienia do niego.
Wpisz WeakMaps
WeakMaps oznacza, że klucze są słabe. Nie ma możliwości wyliczenia słabej mapy ani uzyskania wszystkich jej wartości. Na słabej mapie możesz przechowywać dane w oparciu o klucz, a kiedy klucz zostanie wyrzucony, usuwaj wartości.
Oznacza to, że biorąc pod uwagę obietnicę, możesz przechowywać stan na ten temat - i ten obiekt może być nadal usuwany. Później, jeśli otrzymasz odniesienie do obiektu, możesz sprawdzić, czy masz do niego jakiś stan i zgłosić go.
Zostało to wykorzystane do realizacji nieobsłużonych haki odrzucenia przez Petka Antonov jak to :
Przechowujemy informacje o obietnicach na mapie i możemy wiedzieć, kiedy zrealizowano odrzuconą obietnicę.
źródło
useObj
przykładzie używającym a,Map
a nie aWeakMap
, używamy przekazanego obiektu jako klucza mapy. Obiekt nigdy nie jest usuwany z mapy (ponieważ nie wiedzielibyśmy, kiedy to zrobić), więc zawsze istnieje odniesienie do niego i nigdy nie można go usunąć. W przykładzie WeakMap, gdy wszystkie inne odniesienia do obiektu znikną - obiekt można usunąć zWeakMap
. Jeśli nadal nie jesteś pewien, co mam na myśli, daj mi znaćcalled
przykład jest lepiej napisany przy użyciu jsfiddle.net/f2efbm7z i nie pokazuje użycia słabej mapy. W rzeczywistości można go lepiej napisać na 6 sposobów, które wymienię poniżej.p[key_symbol] = data
. lub 2) unikalne nazewnictwo;p.__key = data
. lub 3) zakres prywatny;(()=>{let data; p.Key = _=>data=_;})()
. lub 4) zastępstwo z 1 lub 2 lub 3. lub 5) zastąpienie / rozszerzenie klasy Promise na 1 lub 2 lub 3. lub 6) zastąpienie / rozszerzenie klasy Promise z krotką potrzebnych członków. - W każdym razie słaba mapa nie jest potrzebna, chyba że potrzebujesz pamięci podręcznej wrażliwej na pamięć.Ta odpowiedź wydaje się stronnicza i bezużyteczna w scenariuszu z prawdziwego świata. Przeczytaj ją w obecnej postaci i nie traktuj jej jako rzeczywistej opcji do niczego poza eksperymentowaniem
Przypadkiem użycia może być użycie go jako słownika dla słuchaczy, mam współpracownika, który to zrobił. Jest to bardzo pomocne, ponieważ każdy słuchacz jest bezpośrednio ukierunkowany na ten sposób działania. Pożegnanie
listener.on
.Ale z bardziej abstrakcyjnego punktu widzenia,
WeakMap
jest szczególnie potężny do dematerializacji dostępu do praktycznie wszystkiego, nie potrzebujesz przestrzeni nazw, aby odizolować jej członków, ponieważ jest to już sugerowane przez naturę tej struktury. Jestem prawie pewien, że możesz poczynić pewne znaczące ulepszenia pamięci, zastępując niewygodne redundantne klucze obiektowe (nawet jeśli dekonstrukcja działa za Ciebie).Przed przeczytaniem, co dalej
Teraz zdaję sobie sprawę, że moje podkreślenie nie jest najlepszym sposobem na rozwiązanie tego problemu i jak zauważył Benjamin Gruenbaum (sprawdź swoją odpowiedź, jeśli nie jest już powyżej mojej: p), problem ten nie mógł zostać rozwiązany regularnie
Map
, ponieważ wyciekłby, dlatego główną siłąWeakMap
jest to, że nie przeszkadza w usuwaniu śmieci, ponieważ nie przechowują referencji.Oto aktualny kod mojego współpracownika (dziękuję mu za udostępnienie)
Pełne źródło tutaj , dotyczy zarządzania słuchaczami, o którym mówiłem powyżej (możesz również zapoznać się ze specyfikacją )
źródło
WeakMap
działa dobrze do enkapsulacji i ukrywania informacjiWeakMap
jest dostępna tylko dla ES6 i wyższych. AWeakMap
to zbiór par kluczy i wartości, w których klucz musi być przedmiotem. W poniższym przykładzie tworzymyWeakMap
z dwoma elementami:Zastosowaliśmy tę
set()
metodę, aby zdefiniować powiązanie między obiektem a innym przedmiotem (w naszym przypadku ciąg znaków). Zastosowaliśmy tęget()
metodę, aby pobrać element powiązany z obiektem. Ciekawym aspektemWeakMap
jest to, że ma słabe odniesienie do klucza wewnątrz mapy. Słaba referencja oznacza, że jeśli obiekt zostanie zniszczony, śmieciarz usunie cały wpis zWeakMap
, zwalniając w ten sposób pamięć.źródło
𝗠𝗲𝘁𝗮𝗱𝗮𝘁𝗮
Słabych map można używać do przechowywania metadanych dotyczących elementów DOM bez ingerencji w wyrzucanie elementów bezużytecznych lub denerwowanie współpracowników na Twój kod. Na przykład możesz użyć ich do numerycznego indeksowania wszystkich elementów na stronie internetowej.
𝗪𝗶𝘁𝗵𝗼𝘂𝘁 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗼𝗿 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗨𝘀𝗶𝗻𝗴 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗮𝗻𝗱 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗧𝗵𝗲 𝗗𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝗰𝗲
Różnica może wydawać się znikoma, poza tym, że wersja słabej mapy jest dłuższa, jednak istnieje zasadnicza różnica między dwoma fragmentami kodu pokazanymi powyżej. W pierwszym fragmencie kodu, bez słabych map, fragment kodu przechowuje odwołania we wszystkich kierunkach między elementami DOM. Zapobiega to gromadzeniu elementów DOM.
(i * i) % len
może wydawać się dziwną kulką, której nikt by nie użył, ale pomyśl jeszcze raz: mnóstwo kodu produkcyjnego zawiera odwołania DOM, które odbijają się w całym dokumencie. Teraz, jeśli chodzi o drugi fragment kodu, ponieważ wszystkie odwołania do elementów są słabe, po usunięciu węzła przeglądarka jest w stanie stwierdzić, że węzeł nie jest używany (kod nie jest dostępny) w ten sposób usuń go z pamięci. Powodem, dla którego powinieneś martwić się wykorzystaniem pamięci i kotwicami pamięci (takimi jak pierwszy fragment kodu, w którym nieużywane elementy są przechowywane w pamięci) jest to, że większe użycie pamięci oznacza więcej prób GC w przeglądarce (w celu zwolnienia pamięci do zapobiegać awariom przeglądarki) oznacza wolniejsze przeglądanie, a czasem awarię przeglądarki.Jeśli chodzi o polifill dla nich, poleciłbym własną bibliotekę ( tutaj @ github ). Jest to bardzo lekka biblioteka, która po prostu wypełni ją bez żadnych skomplikowanych ram, które można znaleźć w innych wypełniaczach.
~ Szczęśliwego kodowania!
źródło
elements
na zero i gotowe: To będzie GCed. & Re „ Referencje DOM, które odbijają się w całym dokumencie ”, w ogóle nie mają znaczenia: gdy główny linkelements
zniknie, wszystkie okólniki będą oznaczone jako GCed. Jeśli twój element utrzymuje odwołania do elementu, którego nie potrzebuje, to popraw kod i ustaw ref na null, gdy skończysz z niego korzystać. To będzie GCed. Słabe mapy nie są potrzebne .elements
wartości null nie pozwoli przeglądarce na GC elementów w pierwszej sytuacji fragmentu kodu. Wynika to z faktu, że ustawiasz niestandardowe właściwości elementów, a następnie można uzyskać te elementy, a ich niestandardowe właściwości są nadal dostępne, zapobiegając w ten sposób GC'edowi. Pomyśl o tym jak o łańcuchu metalowych pierścieni. Oprócz tego masz dostęp do co najmniej jednego ogniwa w łańcuchu, możesz przytrzymać to ogniwo w łańcuchu, a tym samym zapobiec wpadnięciu całego łańcucha przedmiotów w otchłań.Używam
WeakMap
do pamięci podręcznej bezproblemowego zapamiętywania funkcji, które przyjmują obiekty niezmienne jako ich parametr.Zapamiętywanie to fantazyjny sposób powiedzenia „po obliczeniu wartości zapisz ją w pamięci podręcznej, abyś nie musiał jej ponownie obliczać”.
Oto przykład:
Pokaż fragment kodu
Kilka rzeczy do zapamiętania:
źródło
Mam tę prostą przypadek użycia / Przykład dla WeakMaps.
ZARZĄDZAJ KOLEKCJĄ UŻYTKOWNIKÓW
Zacząłem z
User
obiektu, którego właściwości należąfullname
,username
,age
,gender
oraz metodę zwanąprint
która drukuje czytelny dla człowieka podsumowanie innych właściwości.Następnie dodałem Mapę,
users
aby zachować zbiór wielu użytkowników, których kluczem jestusername
.Dodanie kolekcji wymagało również funkcji pomocniczych do dodawania, pobierania, usuwania użytkownika, a nawet funkcji drukowania wszystkich użytkowników w celu zapewnienia kompletności.
Przy włączonym całym powyższym kodzie, powiedzmy NodeJS , tylko
users
mapa ma odniesienie do obiektów użytkownika w całym procesie. Nie ma innych odniesień do poszczególnych obiektów użytkownika.Uruchamiając ten kod interaktywną powłokę NodeJS, tak jak w przykładzie dodaję czterech użytkowników i drukuję ich:
DODAJ WIĘCEJ INFORMACJI DLA UŻYTKOWNIKÓW BEZ MODYFIKOWANIA ISTNIEJĄCEGO KODU
Powiedzmy teraz, że wymagana jest nowa funkcja, w której łącza użytkowników SMP (Social Media Platform) muszą być śledzone wraz z obiektami użytkownika.
Kluczem tutaj jest również to, że ta funkcja musi zostać zaimplementowana przy minimalnej interwencji w istniejący kod.
Jest to możliwe dzięki WeakMaps w następujący sposób.
Dodaję trzy osobne WeakMapy dla Twittera, Facebooka, LinkedIn.
Dodano funkcję pomocnika,
getSMPWeakMap
aby zwrócić WeakMap powiązaną z podaną nazwą SMP.Funkcja dodawania linku SMP użytkownika do danej SMP WeakMap.
Funkcja drukowania tylko użytkowników obecnych na danym SMP.
Możesz teraz dodawać łącza SMP dla użytkowników, również z możliwością, że każdy użytkownik będzie miał łącze na wielu SMP.
... kontynuując wcześniejszy przykład, dodałem łącza SMP do użytkowników, wiele łączy dla użytkowników Bill i Sarah, a następnie wydrukowałem łącza dla każdego SMP osobno:
Teraz powiedz, że użytkownik został usunięty z
users
mapy, dzwoniącdeleteUser
. To usuwa jedyne odniesienie do obiektu użytkownika. To z kolei usunie również łącze SMP z dowolnego / wszystkich SMP WeakMaps (Garbage Collection), ponieważ bez obiektu użytkownika nie ma możliwości uzyskania dostępu do żadnego z jego łączy SMP.... kontynuując Przykład, usuwam użytkownika Billa, a następnie drukuję linki o SMP, z którymi był powiązany:
Nie ma wymogu żadnego dodatkowego kodu, aby osobno usunąć łącze SMP osobno, a istniejący kod, zanim ta funkcja i tak nie zostanie zmodyfikowana.
Jeśli istnieje inny sposób dodania tej funkcji z / bez WeakMaps, prosimy o komentarz.
źródło