Introduzione
Una funzionalità potente che rende JavaScript unico è la sua capacità di lavorare in modo asincrono tramite funzioni di callback. L'assegnazione di callback asincroni ti consente di scrivere codice basato su eventi, ma rende anche il rilevamento dei bug un'esperienza frustrante, poiché il codice JavaScript non viene eseguito in modo lineare.
Fortunatamente, ora in Chrome DevTools puoi visualizzare la totalità dello stack di chiamate dei callback JavaScript asincroni.
Una volta attivata la funzionalità dello stack di chiamate asincrone in DevTools, potrai esaminare in dettaglio lo stato della tua app web in vari momenti. Esplora la traccia completa dello stack per alcuni ascoltatori di eventi, setInterval
,setTimeout
, XMLHttpRequest
,
promesse, requestAnimationFrame
, MutationObservers
e altro ancora.
Durante l'esplorazione della traccia dello stack, puoi anche analizzare il valore di qualsiasi variabile in quel determinato punto di esecuzione del runtime. È come una macchina del tempo per le espressioni del tuo smartwatch.
Attiviamo questa funzionalità e diamo un'occhiata ad alcuni di questi scenari.
Attivare il debug asincrono in Chrome
Prova questa nuova funzionalità attivandola in Chrome. Vai al riquadro Origini di Chrome Canary DevTools.
Accanto al riquadro Call Stack sul lato destro, è presente una nuova casella di controllo per "Asincrono". Attiva o disattiva la casella di controllo per attivare o disattivare il debug asincrono. Tuttavia, una volta attivata, potresti non volerla disattivare mai più.
Acquisisci eventi timer ritardati e risposte XHR
Probabilmente l'hai già visto in Gmail:
Se si verifica un problema di invio della richiesta (il server ha problemi o si verificano problemi di connettività di rete lato client), Gmail tenterà automaticamente di inviare di nuovo il messaggio dopo un breve timeout.
Per capire in che modo gli stack di chiamate asincrone possono aiutarci ad analizzare gli eventi timer ritardati e le risposte XHR, ho ricreato questo flusso con un esempio simulato di Gmail. Il codice JavaScript completo è disponibile al link riportato sopra, ma il flusso è il seguente:
Se guardi solo il riquadro Stack di chiamate nelle versioni precedenti di DevTools, un breakpoint all'interno di postOnFail()
fornisce poche informazioni su dove viene chiamato postOnFail()
. Ma guarda la differenza quando attivi le strutture asincrone:
Con le serie di chiamate asincrone attivate, puoi visualizzare l'intera serie di chiamate per vedere facilmente se la richiesta è stata avviata da submitHandler()
(dopo aver fatto clic sul pulsante Invia) o da
retrySubmit()
(dopo un ritardo di setTimeout()
):
Espressioni di controllo asincrone
Quando esamini l'intero stack di chiamate, anche le espressioni monitorate si aggiorneranno per riflettere lo stato in quel momento.
Valutare il codice da ambiti precedenti
Oltre a osservare semplicemente le espressioni, puoi interagire con il codice degli ambiti precedenti direttamente nel riquadro della console JavaScript di DevTools.
Immagina di essere il Dr. Who e di avere bisogno di un piccolo aiuto per confrontare l'orologio di prima di salire nella Tardis con quello di "ora". Dalla console di DevTools puoi valutare, memorizzare ed eseguire facilmente calcoli sui valori di diversi punti di esecuzione.
Se continui a utilizzare DevTools per manipolare le espressioni, risparmierai tempo perché non dovrai tornare al codice sorgente, apportare modifiche e aggiornare il browser.
Scoprire le risoluzioni delle promesse concatenate
Se pensavi che il flusso simulato di Gmail precedente fosse difficile da comprendere senza la funzionalità di call stack asincrona abilitata, puoi immaginare quanto sarebbe più difficile con flussi asincroni più complessi come le promesse incatenate? Esaminiamo di nuovo l'ultimo esempio del tutorial di Jake Archibald sulle promesse JavaScript.
Ecco una piccola animazione dell'esplorazione delle pile di chiamate nell'esempio async-best-example.html di Jake.
Ottenere informazioni sulle animazioni web
Andiamo più a fondo negli archivi di HTML5Rocks. Ricordi l'articolo di Paul Lewis Animazioni più snelle, efficaci e veloci con requestAnimationFrame?
Apri la demo di requestAnimationFrame e aggiungi un punto di interruzione all'inizio del metodo update() (intorno alla riga 874) di post.html. Con gli stack di chiamate asincrone otteniamo molti più approfondimenti su requestAnimationFrame, inclusa la possibilità di risalire fino al callback dell'evento di scorrimento iniziale.
Individuare gli aggiornamenti del DOM quando si utilizza MutationObserver
MutationObserver
ci consentono di osservare le modifiche nel DOM. In questo semplice esempio, quando fai clic sul pulsante, a <div class="rows"></div>
viene aggiunto un nuovo nodo DOM.
Aggiungi un punto di interruzione in nodeAdded()
(riga 31) in demo.html. Con le strutture di chiamate asincrone attivate, ora puoi eseguire la procedura inversa nella struttura di chiamate fino a addNode()
per arrivare all'evento di clic iniziale.
Suggerimenti per il debug di JavaScript negli stack di chiamate asincrone
Assegna un nome alle funzioni
Se tendi ad assegnare tutti i tuoi callback come funzioni anonime, ti consigliamo di assegnare loro un nome per facilitare la visualizzazione dello stack delle chiamate.
Ad esempio, prendi una funzione anonima come questa:
window.addEventListener('load', function() {
// do something
});
Assegna un nome, ad esempio windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Quando viene attivato l'evento load, viene visualizzato nella traccia dello stack di DevTools con il nome della funzione anziché con l'enigmatica "(funzione anonima)". In questo modo, è molto più facile vedere a colpo d'occhio cosa sta succedendo nella traccia dello stack.
Per saperne di più
Per riepilogare, questi sono tutti i callback asincroni in cui DevTools mostrerà lo stack di chiamate completo:
- Timer:
riprendi da dove è stato inizializzato
setTimeout()
osetInterval()
. - Richieste XHR:
Torna al punto in cui è stata chiamata
xhr.send()
. - Frame di animazione:
riprendi da dove è stata chiamata
requestAnimationFrame
. - Promesse: riprendi da dove è stata risolta una promessa.
- Object.observe: Torna al punto in cui è stato originariamente associato il callback dell'osservatore.
- MutationObservers: Torna al punto in cui è stato attivato l'evento MutationObserver.
- window.postMessage(): esamina le chiamate di messaggistica all'interno del processo.
- DataTransferItem.getAsString()
- API FileSystem
- IndexedDB
- WebSQL
- Eventi DOM idonei tramite
addEventListener()
: Torna al punto in cui è stato attivato l'evento. Per motivi di prestazioni, non tutti gli eventi DOM sono idonei per la funzionalità degli stack di chiamate asincrone. Alcuni esempi di eventi attualmente disponibili sono: "scroll", "hashchange" e 'selectionchange'. - Eventi multimediali tramite
addEventListener()
: Torna al punto in cui è stato attivato l'evento. Gli eventi multimediali disponibili includono: eventi audio e video (ad es. "play", "pause", "ratechange"), eventi WebRTC MediaStreamTrackList (ad es. "addtrack", "removetrack") ed eventi MediaSource (ad es. "sourceopen").
La possibilità di visualizzare la traccia completa dello stack dei callback JavaScript dovrebbe aiutarti a mantenere la calma. Questa funzionalità di DevTools sarà particolarmente utile quando si verificano più eventi asincroni in relazione tra loro o se viene lanciata un'eccezione non rilevata all'interno di un callback asincrono.
Prova a utilizzarlo in Chrome. Se vuoi fornire feedback su questa nuova funzionalità, scrivici nel tracker dei bug di Chrome DevTools o nel gruppo Chrome DevTools.