天天看點

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

使用 Chrome 開發工具調試異步 JavaScript

<a target="_blank" href="http://blog.csdn.net/opengl_es">轉載請保留此句:太陽火神的美麗人生 -  本部落格專注于 靈活開發及移動和物聯裝置研究:iOS、Android、Html5、Arduino、pcDuino,否則,出自本部落格的文章拒絕轉載或再轉載,謝謝合作。</a>

終于又發現一個值得研究的領域,一頭霧水,繼續研究,估計研究明白了,也就能翻譯明白了,也算是一種推動力吧。

FireFox 的調試功能居然把 16G 記憶體 Mac Mini 給卡死了,看來還得用 Chrome,雖然其調試的斷點總是對不到正确的代碼上去,也許還是用得不對吧!

十幾年前,做 Web 開發時,感覺 JS 已經很熟了,有一些規律,雖然說不出來,但對于問題的查找與排除很有效,時隔多年,全然就飯吃了。

幸好有這些個調試工具,真心得用好它們,才能盡快找出問題。

當下 html5 盛行,單個頁面的背後異步活動越來越多,沒有這種調試工具的配合,也确實難以應對。

這種無節制的隐藏于頁面背後的活動,是否會将 flash 在頁面上泛爛的情況,掩藏到頁面背後去呢?

這個确實值得關注......

入門 

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-introduction">Introduction</a>

在 Chrome 的 Canary 版中使能異步調試

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-enable">Enable async debugging in Chrome Canary</a>

捕獲延遲的定時器事件和 XHR 應答

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-timer-xhr">Capture delayed timer events and XHR responses</a>

異步監視表達式

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-watch-expressions">Watch expressions asynchronously</a>

從剛過去的範圍評估執行代碼

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-past-scopes">Evaluate code from past scopes</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-promises">Coming soon: Unravel chained promise resolutions</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-request-animation-frame">Get insights into your web animations</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-mutation-observer">Track down DOM updates when using MutationObserver</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-debugging-tips">Tips for debugging JavaScript in async call stacks</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh#toc-explore-further">Explore further</a>

<a target="_blank" href="http://www.html5rocks.com/ko/tutorials/developertools/async-call-stack/">한국어</a>

<a target="_blank" href="https://github.com/html5rocks/www.html5rocks.com/blob/master/CONTRIBUTING.md">Contribute another</a>

<a target="_blank" href="http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/?redirect_from_locale=zh">使用 Chrome 開發工具調試異步 JavaScript Debugging Asynchronous JavaScript with Chrome DevTools</a>

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

釋出于:2014年3月26日

Published: March 26th, 2014更新于:2014年3月31日

Updated: March 31st, 2014評論數:34

使 JavaScript 獨一無二的一個強大特性就是它的通過回調函數異步工作的能力。設定異步回調可以讓你編寫事件驅動代碼,但它也使得跟蹤問題變得一頭霧水,因為 JavaScript 不是線性執行的。

A powerful feature that makes JavaScript unique is its ability to work asynchronously via callback functions. Assigning async callbacks let you write event-driven code but it also makes tracking down bugs a hair pulling experience since the JavaScript is not executing in a linear fashion.

Luckily, now in Chrome Canary DevTools, you can view the full call stack of asynchronous JavaScript callbacks!

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

A quick teaser overview of async call stacks.

(We'll break down the flow of this demo soon.)

Once you enable the async call stack feature in DevTools, you will be able to drill into the state of your web app at various points in time. Walk the full stack trace for event listeners, <code>setInterval</code>, <code>setTimeout</code>, <code>XMLHttpRequest</code>, promises,<code>requestAnimationFrame</code>, <code>MutationObservers</code>, and more.

As you walk the stack trace, you can also analyze the value of any variable at that particular point of runtime execution. It's like a time machine for your watch expressions!

Let's enable this feature and take a look at a few of these scenarios.

Try out this new feature by enabling it in Chrome Canary (build 35 or higher). Go to the Sources panel of Chrome Canary DevTools.

Next to the Call Stack panel on the right hand side, there is a new checkbox for "Async". Toggle the checkbox to turn async debugging on or off. (Although once it's on, you may not ever want to turn it off.)

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

You've probably seen this before in Gmail:

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

If there is a problem sending the request (either the server is having problems or there are network connectivity issues on the client side), Gmail will automatically try re-sending the message after a short timeout.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

In the diagram above, the methods highlighted in blue are prime spots for this new DevTool feature to be the most beneficial since these methods work asynchronously.

By solely looking at the Call Stack panel in previous versions of DevTools, a breakpoint within <code>postOnFail()</code> would give you little information about where<code>postOnFail()</code> was being called from. But look at the difference when turning on async stacks:

Before

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

The Call Stack panel without async enabled. 

Here you can see that <code>postOnFail()</code> was initiated from an AJAX callback but no further info.

After

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

The Call Stack panel with async enabled. 

Here you can see that the XHR was initiated from<code>submitHandler()</code>, which was initiated from a click handler bound from scripts.js. Nice!

With async call stacks turned on, you can view the entire call stack to easily see if the request was initiated from <code>submitHandler()</code> as it was above, or from<code>retrySubmit()</code> as it is below:

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

From the Call Stack panel, you can also tell if the breakpoint event originated earlier from an UI event like 'click', a <code>setTimeout()</code> delay, or any commonly used async callback event.

When you walk the full call stack, your watched expressions will also update to reflect the state that it was in at that time!

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

In addition to simply watching expressions, you can interact with your code from previous scopes right in the DevTools JavaScript console panel.

Imagine that you are Dr. Who and you need a little help comparing the clock from before you got into the Tardis to "now". From the DevTools console, you can easily evaluate, store, and do calculations on values from across different execution points.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

Staying within DevTools to manipulate your expressions will save you time from having to switch back to your source code, make edits, and refresh the browser.

Flow diagram from JavaScript Promises.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

Notice how the Call Stack panel is pretty short on info when trying to debug promises.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

Wow! Such promises. Much callbacks.

Promise support for call stacks will be ready soon, as the promise implementation is switching from the version in Blink to the final one within V8.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

The Call Stack panel without async enabled.After

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

And with async enabled.

Add a breakpoint within <code>nodeAdded()</code> (line 31) in demo.html. With async call stacks enabled, you can now walk the call stack back through <code>addNode()</code> to the initial click event.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations
使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

If you tend to assign all of your callbacks as anonymous functions, you may wish to instead give them a name to make viewing the call stack easier.

For example, take an anonymous function like this:

And give it a name like <code>windowLoaded()</code>:

When the load event fires, it will show up in the DevTools stack trace with its function name instead of the cryptic "(anonymous function)". This makes it much easier to see at a glance what's happening in your stack trace.

使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations
使用 Chrome 開發工具調試異步 JavaScript(Debugging Asynchronous JavaScript with Chrome DevTools)内容清單Table of ContentsLocalizations

To recap, these are all the asynchronous callbacks in which DevTools will display the full call stack:

Timers: Walk back to where setTimeout() or setInterval() was initialized.

XHRs: Walk back to where xhr.send() was called.

Animation frames: Walk back to where requestAnimationFrame was called.

Event listeners: Walk back to where the event was originally bound with addEventListener().

MutationObservers: Walk back to where the mutation observer event was fired.

Full call stacks will be coming soon for these experimental JavaScript APIs:

Promises: Walk back to where a promise has been resolved.

Object.observe: Walk back to where the observer callback was originally bound.

Being able to see the full stack trace of your JavaScript callbacks should keep those hairs on your head. This feature in DevTools will be especially helpful when multiple async events happen in relation to each other, or if an uncaught exception is thrown from within an async callback.