Tento článek je překladem textu Debugging Asynchronous JavaScript with Chrome DevTools od Pearl Chen a je zveřejněn pod licencí CC BY 3.0.
Úvod
Asynchronní zpracování pomocí callback funkcí je mocnou stránkou JavaScriptu, ale současně se dost špatně ladí.
Naštěstí Chrome Canary DevTools přináší řešení, můžete v něm vidět celý zásobník javascriptových asynchronních volání!

Jakmile povolíte zásobník asynchronních volání v DevTools, můžete se nořit do různých stavů vaší webové aplikace v čase. Můžete procházet celý zásobník handlerů událostí, volání setInterval
, setTimeout
, XMLHttpRequest
, promises, requestAnimationFrame
, MutationObservers
a další.
Jak budete zásobníkem volání procházet, můžete současně analyzovat hodnoty jakékoliv proměnné v daném bodě spuštění vaší aplikace. Funguje to podobně jako stroj času.
Pojďme se podívat na několik scénářů použití.
Jak povolit asynchronní ladění v Chrome Canary
Použijte Chrome Canary (build 35 nebo vyšší). Zobrazte si panel Sources v DevTools.
Hned vedle panelu Call Stack napravo najdete checkbox „Async“. Ten asynchronní ladění zapíná a vypíná.

Zachytávání událostí časovače a XHR odpovědí
Nejspíš jste něco podobného v Gmailu už viděli:

Pokud nastane problém při odesílání požadavku (ať už je problém na serveru nebo v síťové konektivitě klienta), Gmail se po krátké odmlce automaticky pokusí zprávu poslat znovu.
Abychom si to mohli snadno vyzkoušet, vytvořila jsem mockup Gmailu. Funguje dle schématu:

Pokud se podíváte na obyčejný zásobník volání, tak breakpoint na postOnFail()
vám nic moc nenapoví, odkud byla funkce vyvolána. Zkusme zapnout asynchronní zásobník a hned je jasno:
Předtím:

postOnFail()
je ajaxový callback, ale nic víc.Potom:

submitHandler()
, který byl vyvolán obsluhou události click ze scripts.js. Pěkné!
V celém zásobníku pak uvidíme, že požadavek pochází buď z submitHandler()
jako na obrázku výše anebo z retrySubmit()
jako na obrázku níže:

Ze zásobníku také poznáme, zda byl požadavek vyvolán obsluhou události, např. kliknutím nebo metodou setTimeout()
nebo některou z dalších asynchronních metod.
Sledujte výrazy asynchronně
Při procházení asynchronním zásobníkem můžete sledovat vybrané výrazy (watch expression), které budou zobrazovat hodnotu odpovídající patřičnému stavu aplikace v čase!

Změňte minulost aneb jak vykonat kód v minulých rozsazích působnosti (scopes)
Minulost můžete nejen zkoumat, ale také v ní spouštět váš kód pomocí javascriptové console.
Představte si, že jste Doktorem Who a potřebujete porovnat čas před vstupem do TARDIS a „nyní“. Žádný problém.

Ušetří vám to čas. Můžete zůstat a pracovat v DevTools, místo abyste přepínali do vašich zdrojáků, upravovali je, znovu načítali atd.
Brzy uvidíte: použití se zřetězenými promises
A co teprve, pokud používáte promises. Převezmu finální příklad z tutoriálu Jake Archibalda k javascriptovým promises.
Předtím:

Potom:

Podpora pro promises se objeví brzy (doufejme, že v Chrome 36). Pokud si ji chcete vyzkoušet už dnes, můžete si ji v Chrome 33 nebo Chrome 34 zapnout na stránce chrome://flags/#enable-devtools-experiments
povolením Developer Tools experimentů. Po restartu prohlížeče najdete v nastavení DevTools volbu enable support for async stack traces.
Projděme se animací
Můžeme jít ještě dál. Paul Lewis napsal článek Leaner, Meaner, Faster Animations with requestAnimationFrame. Otevřeme si jeho requestAnimationFrame demo a nastavíme breakpoint na začátek metody update()
method (okolo řádku 874) v post.html.
Předtím:

Potom:

Sledování změn DOMu pomocí MutationObserverů
MutationObserver
nám umožňuje sledovat změny v DOMu. V tomto jednoduchém příkladu je po kliknutí na tlačítko přidán na konec dokumentu <div class="rows"></div>
.
Přidáme breakpoint do metody nodeAdded()
(řádka 31) v demo.html a podíváme se na výsledek.
Předtím:

Potom:

Tipy k ladění asynchronního JavaScriptu
Pojmenujte vaše funkce
Pokud používáte ve vašich callbacích anonymní funkce, můžete je místo toho chtít pojmenovat, což procházení asynchonním zásobníkem dost zjednoduší.
Místo anonymní funkce:
window.addEventListener('load', function(){
// do something
});
Zkuste:
window.addEventListener('load', function windowLoaded(){
// do something
});
A výsledek?
S anonymní funkcí:

S pojmenovanou funkcí:

Shrnutí
Přehled asynchronních callbacků, které můžete sledovat v asynchronním zásobníku:
- Timers: metody setTimeout() a setInterval()
- XHRs: zavolání xhr.send()
- Animation frames: volání requestAnimationFrame.
- Event listeners: vysledování až k addEventListener().
- MutationObservers: sledování, jaká událost je vyvolala.
A brzy přibude podpora pro tato experimentální javascriptová API:
- Promises
- Object.observe
Přehled komentářů