Invoering
Een krachtige functie die JavaScript uniek maakt, is de mogelijkheid om asynchroon te werken via callback-functies. Door asynchrone callbacks toe te wijzen, kun je gebeurtenisgestuurde code schrijven, maar het opsporen van bugs wordt ook een huiveringwekkende ervaring, omdat JavaScript niet lineair wordt uitgevoerd.
Gelukkig kun je nu in Chrome DevTools de volledige call-stack van asynchrone JavaScript-callbacks bekijken!
Zodra u de asynchrone call-stack-functie in DevTools inschakelt, kunt u op verschillende tijdstippen inzoomen op de status van uw web-app. Voer de volledige stacktrace uit voor sommige gebeurtenislisteners, setInterval
, setTimeout
, XMLHttpRequest
, beloftes, requestAnimationFrame
, MutationObservers
en meer.
Terwijl u de stacktrace doorloopt, kunt u ook de waarde van elke variabele op dat specifieke punt van runtime-uitvoering analyseren. Het is als een tijdmachine voor je horloge-uitdrukkingen!
Laten we deze functie inschakelen en een paar van deze scenario's bekijken.
Schakel asynchrone foutopsporing in Chrome in
Probeer deze nieuwe functie uit door deze in Chrome in te schakelen. Ga naar het Bronnenpaneel van Chrome Canary DevTools.
Naast het Call Stack- paneel aan de rechterkant is er een nieuw selectievakje voor "Async". Schakel het selectievakje in om asynchrone foutopsporing in of uit te schakelen. (Hoewel als het eenmaal is ingeschakeld, je het misschien nooit meer wilt uitschakelen.)
Leg vertraagde timergebeurtenissen en XHR-reacties vast
Je hebt dit waarschijnlijk al eerder gezien in Gmail:
Als er een probleem is met het verzenden van het verzoek (de server heeft problemen of er zijn problemen met de netwerkverbinding aan de clientzijde), zal Gmail na een korte time-out automatisch proberen het bericht opnieuw te verzenden.
Om te zien hoe asynchrone oproepstapels ons kunnen helpen bij het analyseren van vertraagde timergebeurtenissen en XHR-reacties, heb ik die stroom opnieuw gemaakt met een nep-Gmail-voorbeeld . De volledige JavaScript-code is te vinden in de bovenstaande link, maar de stroom is als volgt:
Door alleen naar het Call Stack-paneel in eerdere versies van DevTools te kijken, zou een breekpunt binnen postOnFail()
u weinig informatie geven over waar postOnFail()
vandaan werd aangeroepen. Maar kijk eens naar het verschil bij het inschakelen van asynchrone stapels:
Als asynchrone call-stacks zijn ingeschakeld, kunt u de gehele call-stack bekijken om eenvoudig te zien of het verzoek is geïnitieerd vanuit submitHandler()
(wat gebeurt na het klikken op de verzendknop) of vanuit retrySubmit()
(wat gebeurt na een setTimeout()
-vertraging) :
Bekijk expressies asynchroon
Wanneer u de volledige call-stack doorloopt, worden uw bekeken uitdrukkingen ook bijgewerkt om de staat weer te geven waarin deze zich op dat moment bevonden!
Evalueer code uit eerdere bereiken
Naast het eenvoudig bekijken van expressies, kunt u rechtstreeks in het DevTools JavaScript-consolepaneel communiceren met uw code uit eerdere scopes.
Stel je voor dat je Dr. Who bent en dat je wat hulp nodig hebt bij het vergelijken van de klok van voordat je in de Tardis stapte met "nu". Vanuit de DevTools-console kunt u eenvoudig waarden van verschillende uitvoeringspunten evalueren, opslaan en berekeningen uitvoeren.
Als u binnen DevTools blijft om uw expressies te manipuleren, bespaart u tijd omdat u niet hoeft terug te schakelen naar uw broncode, wijzigingen moet aanbrengen en de browser moet vernieuwen.
Ontrafel geketende belofte-resoluties
Als je dacht dat de vorige nep-Gmail-stroom moeilijk te ontrafelen was zonder dat de asynchrone call-stack-functie was ingeschakeld, kun je je dan voorstellen hoeveel moeilijker het zou zijn met complexere asynchrone stromen zoals aan elkaar gekoppelde beloften? Laten we het laatste voorbeeld van Jake Archibald's tutorial over JavaScript Promises nog eens bekijken.
Hier is een kleine animatie van het doorlopen van de call-stacks in Jake's async-best-example.html voorbeeld.
Krijg inzicht in uw webanimaties
Laten we dieper ingaan op de HTML5Rocks-archieven. Herinner je de slankere, gemenere, snellere animaties van Paul Lewis met requestAnimationFrame ?
Open de demo requestAnimationFrame en voeg een breekpunt toe aan het begin van de update() -methode (rond regel 874) van post.html. Met asynchrone call-stacks krijgen we veel meer inzicht in requestAnimationFrame , inclusief de mogelijkheid om helemaal terug te lopen naar de initiërende scroll-gebeurtenis-callback.
Spoor DOM-updates op wanneer u MutationObserver gebruikt
MutationObserver
kunnen we veranderingen in de DOM waarnemen. In dit eenvoudige voorbeeld wordt, wanneer u op de knop klikt, een nieuw DOM-knooppunt toegevoegd aan <div class="rows"></div>
.
Voeg een breekpunt toe binnen nodeAdded()
(regel 31) in demo.html. Als asynchrone call-stacks zijn ingeschakeld, kunt u de call-stack nu terugsturen via addNode()
naar de initiële klikgebeurtenis.
Tips voor het debuggen van JavaScript in asynchrone call-stacks
Geef uw functies een naam
Als u de neiging heeft om al uw callbacks als anonieme functies toe te wijzen, kunt u ze in plaats daarvan een naam geven om het bekijken van de call-stack eenvoudiger te maken.
Neem bijvoorbeeld een anonieme functie als deze:
window.addEventListener('load', function() {
// do something
});
En geef het een naam zoals windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Wanneer de load-gebeurtenis wordt geactiveerd, wordt deze weergegeven in de DevTools-stacktrace met de functienaam in plaats van de cryptische " (anonieme functie) ". Dit maakt het veel gemakkelijker om in één oogopslag te zien wat er in uw stacktrace gebeurt.
Ontdek verder
Om samen te vatten: dit zijn alle asynchrone callbacks waarin DevTools de volledige call-stack zal weergeven:
- Timers : Loop terug naar waar
setTimeout()
ofsetInterval()
is geïnitialiseerd. - XHRs : Loop terug naar waar
xhr.send()
werd aangeroepen. - Animatieframes : loop terug naar waar
requestAnimationFrame
is aangeroepen. - Beloften : Loop terug naar waar een belofte is opgelost.
- Object.observe : Loop terug naar waar de callback van de waarnemer oorspronkelijk was gebonden.
- MutationObservers : Loop terug naar de plaats waar de Mutation Observer-gebeurtenis werd geactiveerd.
- window.postMessage() : Loop over berichtenoproepen binnen het proces.
- DataTransferItem.getAsString()
- Bestandssysteem-API
- GeïndexeerdeDB
- WebSQL
- Geschikte DOM-gebeurtenissen via
addEventListener()
: Loop terug naar waar de gebeurtenis is geactiveerd. Vanwege prestatieredenen komen niet alle DOM-gebeurtenissen in aanmerking voor de functie voor asynchrone call-stacks. Voorbeelden van momenteel beschikbare gebeurtenissen zijn: 'scroll', 'hashchange' en 'selectionchange'. - Multimediagebeurtenissen via
addEventListener()
: Loop terug naar waar de gebeurtenis werd geactiveerd. Beschikbare multimedia-evenementen zijn onder meer: audio- en video-evenementen (bijv. 'play', 'pause', 'ratechange'), WebRTC MediaStreamTrackList-evenementen (bijv. 'addtrack', 'removetrack') en MediaSource-evenementen (bijv. 'sourceopen').
Het kunnen zien van de volledige stacktrace van uw JavaScript-callbacks zou de haren op uw hoofd moeten houden. Deze functie in DevTools is vooral handig wanneer er meerdere asynchrone gebeurtenissen plaatsvinden in relatie tot elkaar, of als er een niet-afgevangen uitzondering wordt gegenereerd vanuit een asynchrone callback.
Probeer het eens in Chrome. Als u feedback heeft over deze nieuwe functie, kunt u ons een bericht sturen via de Chrome DevTools -bugtracker of in de Chrome DevTools Group .