Introduzione
Una potente funzionalità che rende unico JavaScript è la capacità di funzionare in modo asincrono tramite le funzioni di callback. L'assegnazione di callback asincroni ti consente di scrivere codice basato sugli eventi, ma rende anche il rilevamento dei bug un'esperienza di strappo, dal momento che JavaScript non viene eseguito in modo lineare.
Fortunatamente, ora in Chrome DevTools puoi visualizzare completo lo stack di chiamate dei callback JavaScript asincroni.
Dopo aver abilitato la funzionalità dello stack di chiamate asincrone in DevTools, potrai visualizzare in dettaglio lo stato della tua app web in vari momenti. Esegui l'analisi completa
degli stack per alcuni listener di eventi, setInterval
,setTimeout
, XMLHttpRequest
,
promise, requestAnimationFrame
, MutationObservers
e altri.
Mentre esegui l'analisi dello stack, puoi anche analizzare il valore di qualsiasi variabile in quel particolare punto dell'esecuzione del runtime. È come una macchina del tempo per le espressioni 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 Stack chiamate, sul lato destro, è presente una nuova casella di controllo per "Async". Seleziona la casella di controllo per attivare o disattivare il debug asincrono. Anche se una volta attivato, potresti non volerlo mai disattivare.
Acquisisci eventi timer ritardati e risposte XHR
Probabilmente hai già notato quanto segue in Gmail:
Se si verifica un problema durante l'invio della richiesta (o il server ha problemi di connettività di rete sul lato client), Gmail proverà automaticamente a inviare di nuovo il messaggio dopo un breve timeout.
Per capire in che modo gli stack di chiamate asincroni possono aiutarci ad analizzare eventi timer ritardati e risposte XHR, ho ricreato il flusso con un esempio fittizio di Gmail. Il codice JavaScript completo è disponibile al link precedente, ma il flusso è il seguente:
Osservando esclusivamente il riquadro Stack chiamate nelle versioni precedenti di DevTools, un
punto di interruzione all'interno di postOnFail()
fornirebbe poche informazioni sulla provenienza
della chiamata di postOnFail()
. Ma guarda la differenza quando attivi
gli stack asincroni:
Con gli stack di chiamate asincroni attivati, puoi visualizzare l'intero stack di chiamate per
vedere facilmente se la richiesta è stata avviata da submitHandler()
(che avviene dopo aver fatto clic sul pulsante Invia) o da
retrySubmit()
(che avviene dopo un ritardo di setTimeout()
):
Controlla le espressioni in modo asincrono
Quando percorri l'intero stack di chiamate, anche le espressioni controllate verranno aggiornate per riflettere lo stato in cui si trovavano in quel momento.
Valuta il codice dagli ambiti precedenti
Oltre a guardare semplicemente le espressioni, puoi interagire con il codice degli ambiti precedenti direttamente nel riquadro della console JavaScript di DevTools.
Immagina di essere il dottor Who e di aver bisogno di un po' di aiuto per confrontare l'orologio del passato con il Tardis "oggi". Dalla console DevTools puoi facilmente valutare, archiviare ed eseguire calcoli sui valori provenienti da diversi punti di esecuzione.
Se rimani all'interno di DevTools per manipolare le espressioni, non dovrai più tornare al codice sorgente, apportare modifiche e aggiornare il browser.
Svela la risoluzione delle promesse incatenate
Se ritieni che il precedente flusso fittizio di Gmail sia difficile da svelare senza la funzionalità asincrona dello stack di chiamate, puoi immaginare quanto sarebbe più difficile con flussi asincroni più complessi come le promesse concatenate? Rivediamo l'ultimo esempio del tutorial di Jake Archibald su JavaScript Promises.
Di seguito è riportata un'animazione che mostra un'animazione degli stack di chiamate nell'esempio async-best-example.html di Jake.
Ottieni informazioni sulle tue animazioni web
Analizziamo più in dettaglio gli archivi di HTML5Rocks. Ricordi il video di Paul Lewis Leaner, Meaner, Faster Animations with requestAnimationFrame?
Apri la demo di richiestaAnimationFrame e aggiungi un punto di interruzione all'inizio del metodo update() (all'incirca alla riga 874) di post.html. Con gli stack di chiamate asincrone, otteniamo molti più approfondimenti su requestAnimationFrame, inclusa la possibilità di tornare all'avvio del callback dell'evento di scorrimento.
Rileva gli aggiornamenti del DOM quando utilizzi MutationObservationr
MutationObserver
ci consente di osservare le modifiche nel DOM. In questo semplice esempio, quando fai clic sul pulsante, un nuovo nodo DOM viene aggiunto a <div class="rows"></div>
.
Aggiungi un punto di interruzione all'interno di nodeAdded()
(riga 31) in demo.html. Con gli stack di chiamate asincroni abilitati, ora puoi riportare lo stack di chiamate tramite addNode()
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 callback come funzioni anonime, puoi assegnare loro un nome per semplificare la visualizzazione dello stack di chiamate.
Prendiamo ad esempio una funzione anonima come la seguente:
window.addEventListener('load', function() {
// do something
});
Assegna un nome, ad esempio windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
Quando si attiva, l'evento di caricamento viene visualizzato nell'analisi dello stack DevTools con il relativo nome della funzione anziché con la criptica "(funzione anonima)". In questo modo è molto più facile vedere a colpo d'occhio cosa sta succedendo nell'analisi dello stack.
Per saperne di più
Ricapitolando, questi sono tutti i callback asincroni in cui DevTools mostrerà l'intero stack di chiamate:
- Timer:
Torna al punto in cui è stato inizializzato
setTimeout()
osetInterval()
. - XHR:
Torna al punto in cui è stato chiamato
xhr.send()
. - Frame animazioni:
torna al punto in cui è stato chiamato
requestAnimationFrame
. - Promesse: Torna al punto in cui una promessa è stata risolta.
- Object.observe: torna al punto in cui era originariamente associato il callback di osservatore.
- MutationObservers: Torna nel punto in cui è stato attivato l'evento osservatore mutazione.
- window.postMessage(): consente di eseguire l'accesso alle chiamate di messaggistica intra-process.
- DataTransferItem.getAsString()
- API FileSystem
- IndexedDB
- WebSQL
- Eventi DOM idonei tramite
addEventListener()
: torna al luogo in cui l'evento è stato attivato. Per motivi legati alle prestazioni, non tutti gli eventi DOM sono idonei per la funzionalità degli stack di chiamate asincroni. Alcuni esempi di eventi attualmente disponibili sono: "scroll", "hashchange" e "selectionchange". - Eventi multimediali tramite
addEventListener()
: torna dove è 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").
Riuscire a vedere l'analisi completa dello stack dei callback JavaScript dovrebbe mantenere quei capelli in testa. Questa funzionalità in DevTools sarà particolarmente utile quando si verificano più eventi asincroni l'uno rispetto all'altro o se viene generata un'eccezione non rilevata da un callback asincrono.
Provalo in Chrome. Se hai feedback su questa nuova funzionalità, scrivici nel tracker dei bug di Chrome DevTools o nel gruppo di Chrome DevTools.