Wprowadzenie
Potężną funkcją, która wyróżnia JavaScript, jest możliwość działania asynchronicznego za pomocą funkcji wywołania zwrotnego. Przypisanie wywołań asynchronicznych pozwala pisać kod oparty na zdarzeniach, ale powoduje też, że śledzenie błędów staje się męczące, ponieważ kod JavaScript nie jest wykonywany w sposób liniowy.
Na szczęście w Narzędziach deweloperskich w Chrome możesz teraz wyświetlić pełny stos wywołań asynchronicznych wywołań zwrotnych JavaScriptu.
Po włączeniu funkcji wywołania asynchronicznego w DevTools możesz analizować stan aplikacji internetowej w różnych momentach. Przejrzyj pełny ślad стека w przypadku niektórych odbiorców zdarzeń, funkcji setInterval
, setTimeout
, XMLHttpRequest
, obietnic, requestAnimationFrame
i innych.MutationObservers
Podczas analizowania ścieżki wywołań możesz też sprawdzić wartość dowolnej zmiennej w danym punkcie wykonywania kodu. To jak wehikuł czasu dla Twoich zegarków.
Włączmy tę funkcję i zobaczmy kilka takich scenariuszy.
Włączanie debugowania asynchronicznego w Chrome
Wypróbuj tę nową funkcję, włączając ją w Chrome. Otwórz panel Źródła w Narzędziach deweloperskich w Chrome Canary.
Po prawej stronie obok panelu Stos wywołań znajduje się nowe pole wyboru „Asynchronicznie”. Zaznacz lub odznacz pole wyboru, aby włączyć lub wyłączyć debugowanie asynchroniczne (chociaż po włączeniu tej opcji możesz nie chcieć jej wyłączać).
rejestrowanie opóźnionych zdarzeń licznika i odpowiedzi XHR;
Prawdopodobnie widzisz to w Gmailu:
Jeśli wystąpi problem z wysłaniem żądania (np. serwer ma problemy lub występują problemy z połączeniem sieciowym po stronie klienta), Gmail automatycznie spróbuje ponownie wysłać wiadomość po krótkim czasie oczekiwania.
Aby pokazać, jak stosy wywołań asynchronicznych mogą pomóc w analizowaniu opóźnionych zdarzeń związanych z timerem i odpowiedzi XHR, odtworzyłem ten przepływ za pomocą przykładowego Gmaila. Pełny kod JavaScript znajdziesz, klikając powyższy link, ale proces wygląda tak:
W poprzednich wersjach DevTools, patrząc tylko na panel Zrzut stosu, punkt przerwania w funkcji postOnFail()
nie dostarczyłby Ci zbyt wielu informacji o tym, skąd jest wywoływana funkcja postOnFail()
. Zwróć uwagę na różnicę po włączeniu asynkronicznych stert:
Po włączeniu nieblokujących stertowników wywołań możesz wyświetlić cały sterownik wywołań, aby łatwo sprawdzić, czy żądanie zostało zainicjowane z poziomu submitHandler()
(co następuje po kliknięciu przycisku przesłania) czy z poziomu retrySubmit()
(co następuje po opóźnieniu setTimeout()
):
Obserwowane wyrażenia niesynchroniczne
Gdy przejdziesz przez cały stos wywołań, obserwowane wyrażenia zostaną zaktualizowane, aby odzwierciedlały stan wyrażenia w danym momencie.
Ocenianie kodu z poprzednich zakresów
Oprócz obserwowania wyrażeń możesz wchodzić w interakcję z kodem z poprzednich zakresów w panelu konsoli JavaScript w Narzędziach deweloperskich.
Wyobraź sobie, że jesteś Doktorem Who i potrzebujesz pomocy przy porównaniu zegara z czasu, gdy wsiadłeś/wsiałaś do TARDIS, z czasem „obecnym”. W konsoli DevTools możesz łatwo oceniać, przechowywać i wykonywać obliczenia dotyczące wartości z różnych punktów wykonania.
Pozostawanie w Narzędziach deweloperskich podczas manipulowania wyrażeniami pozwoli Ci zaoszczędzić czas, który musiałbyś poświęcić na przełączenie się z powrotem do kodu źródłowego, wprowadzenie zmian i odświeżenie przeglądarki.
Rozwiązywanie łańcuchów obietnic
Jeśli poprzednie symulowane działanie Gmaila było trudne do zrozumienia bez włączonej funkcji wywołań asynchronicznych, wyobraź sobie, jak trudne byłoby to w przypadku bardziej złożonych procesów asynchronicznych, takich jak łańcuchowe obietnice. Przyjrzyjmy się jeszcze raz ostatniemu przykładowi z samouczka Jake'a Archibalda o obietnicach JavaScriptu.
Oto krótka animacja pokazująca przeglądanie sterty wywołań w przykładzie Jake'a async-best-example.html.
Wgląd w statystyki dotyczące animacji internetowych
Przyjrzyjmy się bliżej archiwom HTML5Rocks. Pamiętasz artykuł Leaner, Meaner, Faster Animations with requestAnimationFrame Paula Lewisa?
Otwórz demo requestAnimationFrame i dodaj punkt przerwania na początku metody update() (około wiersza 874) w pliku post.html. Dzięki grupom wywołań asynchronicznych uzyskujemy znacznie więcej informacji o requestAnimationFrame, w tym możliwość przejścia aż do wywołania zwrotnego zdarzenia przewijania, które rozpoczęło działanie.
Śledzenie zmian DOM podczas korzystania z MutationObserver
MutationObserver
pozwalają nam obserwować zmiany w DOM. W tym prostym przykładzie po kliknięciu przycisku do elementu <div class="rows"></div>
zostanie dołączony nowy węzeł DOM.
Dodaj punkt przerwania w pliku demo.html (wiersz 31) w bloku nodeAdded()
. Dzięki włączonym asynkronizowanym grupom wywołań możesz teraz przejść przez grupę wywołań od addNode()
do początkowego zdarzenia kliknięcia.
Wskazówki dotyczące debugowania JavaScriptu w asynchronicznych stosach wywołań
Nazywanie funkcji
Jeśli wszystkie funkcje wywołania przypisujesz jako funkcje anonimowe, możesz nadać im nazwy, aby ułatwić wyświetlanie stosu wywołań.
Weźmy na przykład anonimową funkcję:
window.addEventListener('load', function() {
// do something
});
Nadaj mu nazwę, np. windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Gdy zdarzenie load zostanie wywołane, pojawi się w wyświetleniu ścieżki wywołań w DevTools z nazwą funkcji zamiast enigmatycznego komunikatu „(anonymous function)”. Dzięki temu łatwiej jest na pierwszy rzut oka zobaczyć, co dzieje się w wyświetleniu ścieżki sterowania.
Odkryj więcej
Podsumujmy: oto wszystkie asynchroniczne wywołania zwrotne, w których DevTools wyświetla pełny stos wywołań:
- Samowyzwalacze:
znajdź miejsce, w którym inicjowana jest funkcja
setTimeout()
lubsetInterval()
. - XHR:
znajdź miejsce wywołania funkcji
xhr.send()
. - Klatki animacji:
wróć do miejsca, w którym wywołano funkcję
requestAnimationFrame
. - Obietnice: wróć do miejsca, w którym obietnica została spełniona.
- Object.observe: znajdź miejsce, w którym funkcja zwracająca wywołanie zwrotne obserwatora została pierwotnie powiązana.
- MutationObservers znajdź miejsce, w którym zostało wywołane zdarzenie obserwatora mutacji.
- window.postMessage(): przeglądaj wywołania wiadomości w ramach procesu.
- DataTransferItem.getAsString()
- FileSystem API
- IndexedDB
- WebSQL
- Zdarzenia DOM kwalifikujące się do
addEventListener()
: wróć do miejsca, w którym zostało wywołane zdarzenie. Ze względów związanych z wydajnością nie wszystkie zdarzenia DOM kwalifikują się do korzystania z funkcji wywołań asynchronicznych. Przykłady obecnie dostępnych zdarzeń: „scroll”, „hashchange” i „selectionchange”. - Zdarzenia multimedialne za pomocą
addEventListener()
: wróć do miejsca, w którym zostało wywołane zdarzenie. Dostępne zdarzenia multimedialne to: zdarzenia audio i wideo (np. „play”, „pause”, „ratechange”), zdarzenia WebRTC MediaStreamTrackList (np. „addtrack”, „removetrack”) i zdarzenia MediaSource (np. „sourceopen”).
Możliwość wyświetlenia pełnego śledzenia stosu wywołań kodu JavaScript powinna pomóc Ci zachować nerwy. Ta funkcja w DevTools będzie szczególnie przydatna, gdy wiele zdarzeń asynchronicznych występuje w zależności od siebie lub gdy z nieznanego powodu zostanie wyrzucone wyjątkiem z nieobsługiwanego wywołania zwrotnego asynchronicznego.
Wypróbuj to w Chrome. Jeśli chcesz podzielić się opinią na temat tej nowej funkcji, skontaktuj się z nami za pomocą śledzika błędów w Narzędziach deweloperskich w Chrome lub na forum Narzędzi deweloperskich w Chrome.