2017-12-22 151 views
8

Mam dość dobry rozmiar javascript (z reżimem/redux ale nie jquery) dla budowanej przeze mnie aplikacji webowej i zauważyłem, że kiedy wielokrotnie otwieram i zamykam pewien panel w interfejsie, liczba słuchaczy według czasu działania Chrome stale rośnie.Jak mogę znaleźć miejsce, w którym dodaje się program nasłuchujący zdarzenia?

wykres wygląda następująco: Graph of timeline

I pozwoliły uruchomić monitor wydajności Chrome za dobrą minutę lub dwie z strony siedzi bezczynnie (tuż po otwarciu/zamknięciu panelu pęczek), mając nadzieję, że może słuchacze otrzymają śmieci zebrane, ale tak nie jest. W trakcie tego procesu przełączyłem się na inne zakładki, mając również nadzieję, że słuchacze otrzymają śmieci zebrane, gdy zakładka jest w tle, ale niestety tak nie jest.

Podejrzewam, że niektórzy słuchacze są rejestrowani, a nigdy nie są rejestrowani.

To prowadzi mnie do dwóch podstawowych pytań:

  1. Czy moja hipoteza, że ​​słuchacze są dodawane uzyskiwanie i nigdy niezwiązany wydaje się sensowne, czy jest tam jeszcze mogę zrobić, by potwierdzić te podejrzenia?
  2. Zakładając, że moje podejrzenie jest poprawne, jak najlepiej odejść w sprawie śledzenia kodu, w którym znajduje się obiekt nasłuchiwania zdarzeń? . Próbowałem już:
    • Sprawdzono kod, który jest odpowiedzialny za otwarcie danego panelu, sprawdzając, gdzie dodaje on wszystkich słuchaczy, i komentując te fragmenty, aby zobaczyć, czy są jakieś zmiany w wykresie wydajności. Nie ma zmiany.
    • Zastąpiona prototyp addEventListener tak:

 

var f = EventTarget.prototype.addEventListener; 
EventTarget.prototype.addEventListener = function(type, fn, capture) { 
    this.f = f; 
    this.f(type, fn, capture); 
    console.trace("Added event listener on" + type); 
} 

Nawet po zrobieniu tego, czym komentując wszystkie fragmenty kodu, które powodują ten console.trace do wykonania (patrz # 1) tak, że plik console.trace nie jest już drukowany na otwartym/zamkniętym panelu, zauważam ten sam wzrost w słuchaczach na wykresie wydajności. Coś innego powoduje wzrost słuchaczy. Rozumiem, że istnieją inne sposoby dodawania słuchaczy, ale nie jest dla mnie jasne, jak przechwycić wszystkie te możliwości lub spowodować, że będą one logowane w debugerze Chrome w taki sposób, żebym mógł stwierdzić, który kod jest odpowiedzialny za ich dodanie .

Edit: - Na sugestię cowbert w komentarzach, wziąłem do obejrzenia tej strony: https://developers.google.com/web/tools/chrome-devtools/console/events

Potem złożył następujące funkcję:

function printListenerCount() { 
    var eles = document.getElementsByTagName("*"); 
    var numListeners = 0; 
    for (idx in eles) { let listeners = getEventListeners(eles[idx]); 
     for(eIdx in listeners) 
     { 
      numListeners += listeners[eIdx].length; 
     } 
     console.log("ele", eles[idx], "listeners", getEventListeners(eles[idx])); 
    } 
    console.log("numListeners", numListeners) 
} 

I wykonanie tego funkcja po kilkukrotnym otwarciu/zamknięciu panelu, ale niestety liczba "numListeners" się nie zmienia. Jeśli liczba numListeners zmieniłaby się, byłbym w stanie zmienić wyniki przed/po otwarciu/zamknięciu panelu, aby odkryć, który element ma zarejestrowany dodatkowy detektor zdarzeń, ale niestety numListeners się nie zmienia.

Istnieje również funkcja API monitorEvents() opisana w https://developers.google.com/web/tools/chrome-devtools/console/events, ale funkcja wymaga określenia elementu DOM, który ma być monitorowany. W tej sytuacji nie jestem pewien, który element DOM ma dodatkowe detektory , więc nie jestem pewien, w jaki sposób wywołanie monitorEvents() naprawdę mi pomoże. Mogłem dołączyć go do wszystkich elementów DOM, podobnie jak miałem napisałem powyższą funkcję printListenerCount, ale przypuszczam, że napotkałem podobny problem, który napotkałem z printListenerCount() - z jakiegokolwiek powodu, to nie jest rozliczanie danego słuchacza (ów).

Inne uwagi: Jest to dość skomplikowana aplikacja reagjs (preact, technicznie). Podobnie jak większość aplikacji opartych na responsjach, komponenty są montowane/odłączane (wstawiane i usuwane z DOM) w locie. Zauważyłem, że to sprawia, że ​​śledzenie "bezpańskich rejestratorów zdarzeń" jest trochę skomplikowane. Tak naprawdę mam nadzieję, że jest kilka ogólnych porad dotyczących debugowania, jak wyśledzić "Zabłąkane programy obsługi zdarzeń" w dużych/złożonych projektach takich jak ten. Jako programista C, otworzę gdb i ustawię punkt przerwania na wszystko, co może spowodować zwiększenie liczby "słuchaczy" na wykresie wydajności. Nie jestem pewien, czy istnieje analogia w świecie javascript, a nawet jeśli tam jest, po prostu nie jestem pewien, jak to zrobić. Każda rada byłaby doceniona!

+1

Czy próbowałeś spojrzeć na API monitorEvents() w chrome? https://developers.google.com/web/tools/chrome-devtools/console/events – cowbert

+0

Dzięki, przyjrzałem się temu i dodałem notatki do mojego OP. – Andrew

+0

Możesz spróbować wyszukać wszystkie wystąpienia addEventListener w kodzie i umieścić na nich punkt przerwania. Nie powinno to być bardzo różne od tego, co otrzymałeś z prototypową wymianą, chyba że ktoś robi to samo, zanim to zrobisz ... – jcaron

Odpowiedz

0

Dzięki za komentarze, wszyscy. W końcu to rozgryzłem.

Z mojego OP:

  1. Czy moja hipoteza, że ​​słuchacze są dodawane uzyskiwanie i nigdy niezwiązany rozsądne wydaje, czy jest tam jeszcze mogę zrobić, by potwierdzić te podejrzenia?

Okazuje się, że odpowiedź na to pytanie brzmi: Hipoteza nie jest sensowna. Słuchacze po prostu nie mieli okazji, by jeszcze zebrać śmieci. To może zająć trochę więcej czasu, niż mogłoby się wydawać.

Oto jak to rozgryzłem: Nie udało mi się zrozumieć, że podczas nagrywania osi czasu można wymusić odśmiecenie, klikając ikonę kosza na zakładce Wydajność (ta sama zakładka służy do rozpoczęcia nagrywania na linii czasu). Po kliknięciu tej ikony po wielokrotnym zamknięciu/otwarciu panelu interfejsu, dodatkowi słuchacze całkowicie odeszli. Na wykresie wygląda teraz tak, ze spadki są momenty gdzie kliknąłem ikonę kosza: Performance timeline with manual GC

Podobno w tło kartę i czeka kilka minut, jak już wspomniano w PO po prostu nie jest wystarczająco dużo czasu na zbieranie śmieci wystąpić samodzielnie; To zajmuje więcej czasu.

Nie wiedziałem o możliwości ręcznego zbierania śmieci z ikoną kosza na śmieci, gdy napisałem OP ... Zdecydowanie zaleca się używanie go przed wyruszeniem w dowolną dziką gonitwę poszukiwanie czegoś, co na pierwszy rzut oka może wyglądać jak problem z wydajnością.

+2

Czy nie jest to "problem z wydajnością", ponieważ źle zrozumiałeś/źle zinterpretowałeś wykres?Oznacza to, że nie było żadnego rzeczywistego, zmierzonego problemu z wydajnością, myślałeś, że jest jeden i skończyło się ściganiem twojego ogona przez jakiś czas. Może się to zdarzyć każdemu, oczywiście, ale rozwiązaniem nie jest "znajdowanie przycisków w interfejsie narzędziowym, które spowodują, że wyimaginowane problemy znikną", ale "starają się lepiej zrozumieć środowisko uruchomieniowe i to, co mówią narzędzia. ". Nie jestem pewien, czy wniosek, który przedstawiłeś jako odpowiedź, jest dobry. – pvg

+0

Zastanawiam się, czy to dlatego, że po "usunięciu" obiektu, domyślnie preact/nadal buforuje go w przypadku, gdy chcesz ponownie przerysować go ponownie, i jest buforowany z jego obsługi wciąż związany. – cowbert

+0

Tak, w moim PO napisałem następujące pytanie: "Czy moja hipoteza, że ​​słuchacze są dodawane i nigdy nie jest niezwiązana wydaje się rozsądna, czy może więcej mogę zrobić, aby potwierdzić to podejrzenie?". Okazuje się, że odpowiedź na to pytanie brzmiała: "Twoje podejrzenie, że istniał prawdziwy problem z wydajnością, było niepoprawne, oto jak mógłbyś lepiej dokonać tej determinacji ...". Wydaje mi się, że jasno wyraziłem w mojej odpowiedzi, kiedy powiedziałem: "Hipoteza nie jest rozsądna". Jeśli uważasz, że to nie jest jasne, czy możesz wskazać dlaczego? Dzięki. – Andrew