英文原文:THE WEBKIT INSPECTOR,編譯:oschina
當今移動裝置這邊廂風景已由WebKit獨領風騷,所以,為移動裝置上Web前端開發提供支援的各種工具以及基礎設施都來自WebKit的Inspector。因此,我將著重講述一下WebKit的Inspector,深入闡述它所具有的全部特性集,並說說應該在什麼情況下以及如何使用WebKit的Inspector。
Google以及Chrome團隊已經給出了大量關於Inspector的資料。正是由於這方面的發展變化,才使得整個一大類新的比較複雜而炫目的應用程式能夠克服自身巨大的複雜性而成為現實。這當然是個好訊息,但隨著我不斷地同越來越多的Web開發人員交談,我逐漸發現,他們中有很多人在開發過程以及工具使用方面,並沒有及時跟進這些變化,或者說,他們並沒有充分利用現有的工具。為了彌補該問題,我這篇博文不僅會帶領你領略Inspector的所有特性,而且還會重點介紹一些查詢bug的技術以及一些我認為不可或缺的特性開發技術。寫本博文就是為了要它即可看又可分享。你可以點選本文中的任何一個小標題,將指向特定技巧/技術或特性的URL分享給你的朋友們(譯者注:由於翻譯排版的問題,這個功能就木有了)。
寫在前面
在我們開始深入探討之前,要宣告一點就是我並不認為我在開發過程以及工具使用方面的知識是絕對正確的。如果你發現其中觀點有誤、資訊過時或者用處不大,請給我發封email告訴我你的觀點,我將洗耳恭聽。
如果你剛結識inspector,或者對它瞭解並不多,那就勞駕您邊讀本文邊擺弄擺弄它。親身試驗是最好的學習方法!“但是寶貝啊,我可不想為了試驗這些東西而不斷地建一堆新檔案然後載入並編輯它們!我還要喂孩子呢!”。 我聽到你這麼說了,而且我也贊同你的這個觀點,這也正是為什麼會有“data:URLScheme”的原因!
請試驗一下: 在Chrome中開啟一個新標籤(tab),把下列內容貼上到位址列並敲擊Enter鍵:
1 |
data:text/html,<b>ZOMG I AM BOLD!?!!?</b> |
這是在頁面中弄一些HTML並檢視其展示情況、試驗一些新想法最簡便的方法。冒號後面的所有內容都會被瀏覽器看作是HTML,一旦裝載完成後,就可以開啟Inspector進行各種試驗了。
一個Inspector就夠了
WebKit上現在可不止有一個Inspector。實際上任何時候你都可以使用以下所列瀏覽器裡提供的5個Inspector:
- Safari Stable
- Chrome Stable
- WebKit Nightlies
- Chromium
- Chrome Canary
我是按照從最舊到最新的順序對它們進行排列的。Chrome Canary總能得到最新特性方面的更新。在最早嚐鮮的人用過一段時間之後,這些新特性會逐漸併入Chromium、WebKit Nightlies以及Chrome,最後併入的是Safari。在任何時候,Safari的Inspector都落後於Chrome Canary大約一年的開發時間。也就是說,請你使用Chrome Canary進行開發吧。
設定好環境
棒極了。你已經下載並開啟了Chrome Canary,啟動了你的網站之後,你摩拳擦掌並挽起了袖子。 請敲擊按鍵CMD+J開啟Inspector,也可以用滑鼠右鍵點選某一個的元素並單擊“Inspect Element”選單。
現在來設定一個舒服的環境。要做的第一件事是先熟悉一下UI。花點時間點選一下你所看到的每一個按鈕,還可以在按鈕上懸停一下滑鼠,檢視按鈕的提示資訊(tooltip),看看到底它們能幹些什麼事情。
停靠到右側
你要做的第一件事是,點選介面底端右側的齒輪圖示,調出Inspector的設定介面。先別管設定介面那極其醜陋的平視顯式格式(HUD display), 我強烈推薦選擇“Dock to Right”這個選項(譯者注:其實可以把Inspector拖到右側停靠)。選擇該選項後,Inspector就會停靠在視窗右側。你要是將Inspector彈出為獨立視窗,再同時開啟多個Inspector,情況就會很混亂。如果停靠在底部,那麼水平方向的許多空間得不到利用,反而垂直方向上能看到的內容太有限了。停靠到右側能在雙方面達到最好的效果。你所看到的應該是如下圖所示的情況:
模擬觸屏事件
如果你正在開發的是移動應用,那麼這個設定(在設定介面裡)就很有必要選擇了。
Google啊,如果你在聽我說的話:把那個“Dock to Right”作為預設選項選擇上吧!
快捷鍵
還有一個小技巧可以幫你提高使用Inspector的效率,就是熟練使用鍵盤快捷鍵。 切換到Elements皮膚(有些其它皮膚會吞掉鍵盤敲擊事件),然後鍵入“?”。 隨後就會出現極其醜陋的平視顯式格式的介面,其中列出了一個快捷鍵列表。最有用的快捷鍵是切換到Script皮膚的那個,隨後我們再細說這些。
Google啊,如果你在聽我說的話:把快捷鍵列表放到設定皮膚中吧。多數人都不知道要按那個神祕的問號鍵。既然說到這了,那就再問問,為什麼這個列表介面的顏色同其它的UI如此不同?為什麼邊框圓角的半徑那麼大?為什麼標題欄裡的那個“X”按鍵沒有垂直對中?為什麼其中有些快捷鍵小到根本無法看清?
檢視iFrame
一直以來,iFrames的除錯都是擺在Web開發人員面前的一個難題。現在再也不是了!你現在可以指定想讓Inspector檢視哪個iFrame,指定的方法是通過下圖所示的inspector底端中間部分的彈出式選擇框進行。這個選擇框有些稀奇,只有你對控制檯進行擴充套件(在Elements皮膚下按Esc鍵)之後才能顯示出來。
Google啊,如果你在聽我說的話:把iFrame下拉選擇框放到觸手可及的地方吧。
控制檯
甜心大寶貝,你環境都弄好了, 音樂也響起了,此時心必嚮往之。現在你需要真的做些事情了:執行命令,檢查某個函式的輸出結果,看看某個方法是否存在,或者看看有什麼日誌/錯誤/警告。這些都是控制檯可以幫助你乾的事情。 控制檯可是個到處惹是生非的壞傢伙,實際上它不僅僅有自己的皮膚,而且在任何皮膚中都可以通過點選介面底部左側的“>=”圖示或者按Esc鍵把它調出來使用。
它正好也是比較直觀的功能之一: 鍵入一些表示式並敲Enter鍵,然後就能看到相應的輸出結果。日誌按發生時間順序顯示,點選右側的檔名就可以到達Scripts皮膚。但你可能還不知道,在控制檯皮膚中使用“shift + enter”,你可以鍵入多行表示式。這對編寫包含匿名函式或複雜語句的比較長的命令十分有幫助。你還可以在日誌多得看不過來的情況下,鍵入“ctrl + L”清除控制檯中顯示的內容。
從DOM除錯的角度看,控制檯裡比較酷的一個功能是它可同Elements皮膚(這個我們在下一節中進行討論)進行整合。在Elements皮膚選中的元素可以便捷地通過使用 “$0”進行訪問。它代表對選中元素的引用,你可以對該元素進行一些互動操作。另一方面,只要你在控制檯中看到有列印出來的DOM節點,你都可以右擊該節點並點選“Reveal in Elements Panel”選單就可以在DOM中快速找到該節點了。
Google啊,如果你在聽我說的話:給控制檯的命令加上語法高亮吧,這對排除簡單的錯誤會很有幫助作用的。要是能自動插入大小括號以及引號的話,倒也傷害不了誰。
Elements皮膚
你設定好了環境並準備好開始建立你的應用程式了。第一步是要讓你的HTML和CSS表現正常(或者還有JavaScript,這取決於你的工作流程)。此時就是該Elements皮膚上場大顯身手的時候了。
DOM操作
Elements皮膚在你需要修改/除錯CSS或者DOM時就該派上用場了。Elements皮膚的主要區域裡實時地顯示著你的DOM的層次結構。隨著你用JavaScript對它們進行修改,你就能在Elements皮膚中實時的看到修改的結果。箭頭鍵可以用來在層次結構中上下游走,而且你還可以雙擊任意屬性對其名或其值進行編輯。你還可以在DOM中點選後拖拽任意節點重新排列節點順序並改變它們的位置。
因為Elements皮膚反映的是實時資訊,所以我發現我自己經常會在這個皮膚進行大量的試驗。將這個節點拖拽到這裡,看看是不是修復了z座標方向的顯示順序問題(z-index ordering issue)? 那個DIV沒有顯示出來,看看它是不是被另外一層給遮擋住了?
在inspector的底部,你能看到有個放大鏡。你點選它之後,就可以將其懸停在你的應用之上,放大鏡就會高亮顯示你選擇的節點。這一招在你需要快速選擇一個巢狀層次非常深的元素時會非常方便。
你在Elements皮膚裡這試試那試試時,用滑鼠右鍵點選任何一個節點,看看會彈出些什麼選單。其中有一個選單是“Break on Subtree Modifications(子樹發生修改時暫停執行)”。 你選上它後,對滑鼠下那個節點下的所有DOM節點進行修改時,瀏覽器會自動暫停,給你個除錯的機會。
CSS的編輯
接下往右看,會看到CSS編輯器,它可是Inspector最有用的特性之一。粗淺說來,用它可以對你的CSS進行實時編輯。但是,它大大減少了試驗所需克服的障礙,我發現我經常在該編輯器中挪東挪西,對各種想法進行試驗。要不是它提供這麼便利的試驗條件,我那些想法可能早就因為被認為愚蠢到家而被直接拋棄了;正如Bret Victor 所說,這可是一件大好事。
右側列表中你首先看到的是“Computed Style×(計算所得樣式)”部分。選中“Show inherited(顯示繼承項)”檢查框,你就能看到由左側選中的節點所適用的所有樣式屬性極其取值組成的一個列表。 及時你沒有顯式地設定某個屬性,它也會顯示出它所繼承的預設值。 這樣不僅僅可以幫你理解一個節點的樣式到底是由哪些屬性組成的,而且還可以幫你找出修改該節點樣式所需設定的屬性。請你看看那些屬性中有沒有你還不知道的屬性,然後修改一下它看看它到底有什麼作用。
列表中的下一項是“Styles(樣式)”部分。在這部分將左側選中的節點所適用的屬性按照選擇器進行分組顯示。 第一個子部分標題是“element.style”,它顯示的是在HTML中通過style=””設定的所有屬性。接下來的子部分標題為“Matched CSS Rules(相匹配的CSS規則)”,顯示的是同所選節點向匹配的選擇器以及其中的屬性和值,並且右側還顯示了選擇器所在的檔名以及行號(line number)。
要新增新的選擇器,可以點選“Styles”標題欄右側的“+”按鈕, 這裡你可以定義選擇器,適用tab鍵,書寫屬性及其值。你會發現,Chrome提供了自動補全建議(這是調查你能設定哪些屬性的另一個很好的方法)。撰寫本文時所用的最新版的Canary要求敲擊右箭頭鍵來完成自動補全動作,接下來可以按tab鍵並設定屬性的值。再次敲擊tab鍵就可以進行下一個屬性設定了。如果你想在已有的選擇器中設定一個新屬性,點選一次結尾的括號然後點選“+”新選擇器右邊的按鈕就能讓你指定一個偽選擇器了(a pseudo selector)。這真是太方便了!
顏色的表現稍有不同。單擊一個顏色值,會讓顏色值在不同的表示方式(16進位制, rgb, rgba等等)之間來回切換顯示, 單擊帶顏色的小方塊會開啟顏色選擇器。
所有這些都很好,但讓我們假設一下,你已經花了10分鐘對CSS進行了各種編輯,然後呢?你怎樣儲存這些修改呢?要儲存修改,就要點選選擇器的檔名(或者你自己到資源皮膚中找到相應的檔案),接下來滑鼠右擊該檔案(該檔案將更新以反映那些修改操作),然後就可以點選“Save As”選單覆蓋你已有的檔案了。個人經驗,我發現選擇文字並將其貼上到我的編輯器中速度更快而且還不容易出錯。
最後在CSS編輯方面要注意的一點是:如果你新增了新的選擇器(通過敲擊“+”鍵),那麼該選擇器不會被儲存到檔案中,因為Inspector不知道要將這個新選擇器儲存到哪個CSS檔案中。
Google啊,如果你在聽我說的話:要是我建立了一個新的選擇器的話,完全可以問我想把這個新選擇器儲存到哪個檔案中。還有,用“tab”鍵完成所選的自動補全操作吧。最後還有,找找看有沒有更好的把CSS中的修改儲存到我的程式碼中的方法。最後這個要求屬於比較高階的要求,我並不知道它是否可行,更不知道這個好方法應該是個什麼樣子,我就是想讓整個工作過程更加的流暢一些:P。
Metrics(尺寸大小)
嘖嘖,一下子說了這麼多內容!花點時間擺弄擺弄這些東西吧。擺弄的差不多了,我們就來看下一項內容:Metrics。如果你還不熟悉CSS的盒子模型(Box Model),那就先去看看這篇非常棒的指南。
Metrics部分顯示的是瀏覽器是如何按照內容的尺寸、填充空間(padding)、邊框(border)和邊距(margin)來渲染(render)節點的。這個工具用來除錯位置/尺寸問題。
Metrics皮膚有一個非常好用的小技巧,覆蓋在所選節點之上的那個半透明的藍色盒子可以用來顯示出填充空間和邊距,從而幫助你看明白盒子是如何影響流(flow)的。
藍色部分表示的是內容,綠色部分是填充空間,橘色部分是邊距。
事件偵聽器(Event Listener)
我們暫時先跳過屬性和DOM斷點這兩個部分。我還沒發現屬性部分有什麼用處,DOM斷點顯示的是滑鼠右擊節點後選定的各種“Break on …”動作。我們在Elements皮膚中最後要討論的就是事件偵聽器部分。
如果你為選中的節點新增了任何事件偵聽器的話(用JavaSctip或者HTML的屬性都可以新增),你就能在這裡看到所有你所新增的偵聽器。這個部分便於你想除錯一個偵聽器是否正確的新增到了某個節點上,還能幫你瞭解當偵聽器得到呼叫後會發生什麼。
單擊小標題右側的漏斗圖示,可以在檢視所選節點的偵聽器和整個文件的偵聽器之間進行切換。如果你的偵聽器新增到了無法在主列表中進行選擇的東西(比如window和document)上時,會非常有用。
資源皮膚(Resources Panel)
你的HTML和CSS看起來表現不錯,並且你寫了不少的JavaScript程式碼,使用了檔案系統API、IndexedDB、LocalStorage、應用緩衝區(App Cache)以及Cookies。資源皮膚就是用來讓你所有這些儲存資源進行檢視和除錯的。裡面大部分的東西或多或少都幾乎相同,也都相當的不言自明:單擊一類資源就能看到一個專案(item)列表,一步步點選深入進去就可以找到你的資料。
裡面的叫做“Frames”的第一項需要注意。它包含了你的應用中的所有frame,每個frame都按照圖片、指令碼和樣式表分組列出所有資源。實際上,我深挖Frames列表的唯一的原因,就是去找我所編輯的樣式表檔案,然後把檔案的內容拷貝貼上到我們的編輯器中進行儲存。
網路皮膚
除錯網路問題時,直接可以用網路皮膚。圖片檔案沒有更新?網路皮膚會告訴你它是不是從快取載入的。XHR(非同步請求)沒有響應?網路皮膚可以告訴你它被卡住或者出錯。
點選“記錄”按鈕(黑色圓鈕),在重新載入時將維護一個網路會話,如果你想看到程式碼的變化如何影響網路效能。
如果你在除錯效能問題,網路皮膚很有幫助。在右側,你可以看到網路請求的“級連瀑布流”。如果頁面花費了非常長時間載入,除錯的第一步應該是檢視瀑布流。藍色和紅色的豎線顯示DOMContentLoaded事件的時間,意味著在該時間點之前,使用者一直在焦急的等待。你需要儘量減少該時間。
瀑布
有位客官問了,為什麼我老把右邊那部分內容叫做瀑布呢?噢,因為它的樣子看上去和瀑布很像,但更重要的是,很像瀑布的原因在於,每次網路互動所花的時間包括網路延遲和檔案下載所花的時間這個兩個部分,而且在檔案下載時,瀏覽器只能夠並行下載一小部分檔案。如果你的瀑布看上去很寬,那麼你就需要改變一下方式,縮減HTML中HTTP請求的總數了。
還有,你可以通過點選“Timeline(時間線)”的標題欄得到一個下拉選擇框來改變時間線的排序方式。特別值得關注的是按照“Latency(時延)”進行排序,就能夠看到在所有請求中,建立連線所花的時間最長的是哪個請求。
橫條左側半透明的部分顯示的是時延,深色部分是檔案下載所花的時間。
網路請求的細節
在網路皮膚的底部, 單擊“XHR”可以只顯示XMLHttpRequest所涉及的網路連線。隨後再點選其中的一項,介面右側顯得的就變成了剛才點選的那個網路請求的細節性資訊了。第一個標籤下顯示的是該網路請求過程中所傳送的全部HTTP頭部(header)以及響應資訊。這些資訊在除錯伺服器或者CORS的bug時非常有用。
Preview(預覽)下顯示的是格式化之後的響應資訊。如果你獲得的是大量JSON資料, 預覽標籤下它們就會以可摺疊方式進行顯示,而在響應標籤下它們只是以普通文字的方式顯示的。
Cookies顯示的是網路請求過程中傳送的所有cookies,時序資訊(Timing)顯示的是網路請求處理過程中的時間資訊。時序資訊在網路請求所花時間過長時同樣也是很有用的。
Scripts皮膚
我是一名專職的JavaScript開發人員,也就是說,在我工作當中的大部分時間我都花在這個皮膚上了。這個也是最近變化最大的皮膚之一。
環顧四周,這裡有兩個按鈕有必要說一下。 “Pretty Print”按鈕(看上去象一對花括號)用來對最小化(minified)的檔案內容進行恰當的排版。如果你發現在第三方最小化的程式碼包中發現有一個bug而且還想搞清除bug的來龍去脈時,這個按鈕將會非常有用。
另一個要說一下的是“Break on Exception”按鈕(看上去象個暫停按鈕)。如果它是灰色的,那麼它就是處於禁用狀態。單擊該按鈕就會讓你的指令碼在丟擲任何異常時暫停執行。再單擊一次該按鈕,它就會處於 “Break on Uncaught Exception”模式,這時只有在指令碼丟擲的異常沒有被捕獲時才會暫停執行。這個按鈕不可或缺,當你想要跟蹤指令碼丟擲的異常時,它能保留住異常丟擲時的呼叫棧以及應用當時的所有狀態。
檔案導航區
主要工作區中標籤外帶了一個完整的檔案瀏覽器,以檔案的來源對所有檔案進行劃分,這大大改善了到處胡亂檔案的效率。
要開啟檔案瀏覽器,單擊左上角那個奇怪的圖示(用一個帶直角拐彎的線連線起來的兩個資料夾)。預設情況下,檔案瀏覽器會“漂浮”在工作區之上, 所以,你要單擊一下檔案瀏覽器右上角那個奇怪的圖示(半白半黑的矩形),將檔案瀏覽器停靠在工作區中。你可以試著在檔案瀏覽器中敲幾個鍵,它就能通過模糊匹配的方式定位到其中的檔案!
既然說到在很多檔案中查詢想要的檔案了,不得不再說一下,敲擊“CMD+O”鍵會彈出一個TextMate風格的“Go-to-File”彈出式檔案定位器,可以讓你快速定位都一個檔案。“CMD + Shift+ O”會彈出一個“Go-to-Symbol”彈出式符號定位器,可以讓你快速地定位到當前檔案中的一個符號。,“CMD + L”可以讓你快速定位都某一行。
Google啊,如果你在聽我說的話:在Go-to-File檔案定位器中新增上檔案的路徑吧,因為可能會出現檔名重複的情況。
斷點
單擊程式碼區左側的側邊欄中的行號(line number)會插入一個斷點。如果你的應用執行到了這一行程式碼,就會暫停執行後彈出指令碼皮膚,並高亮顯示本行程式碼。隨後,你便可以檢視呼叫棧,能夠訪問到的變數,還可以檢視/修改物件。這個就是除錯JavaScript程式碼問題的主要工作流程。
你偶爾可能會想除錯熱點程式碼(hot code,執行次數非常之多的程式碼)中出現的問題。這時插入斷點就會非常麻煩,因為在執行過程中你不得不經常點選“Continue(繼續執行)”按鈕。通常在這種情況下,我會用類似“window.foo = true”和“window.foo = false”這樣的條件來過濾想要除錯的函式執行情況。滑鼠右鍵點選斷點,單擊 “Edit Breakpoint(編輯斷點)”選單,就可以在文字輸入框中輸入“window.foo”。這是告訴Inspector,只有在window.foo取值為true的情況下才暫停執行。
現在,你加好了斷點,重新整理了頁面,指令碼執行暫停了下來。接下來的事就會非常有意思了。
第一個要注意的是側邊欄的“Watched Expressions(受監視的表示式)”。如果你非常關係某些表示式的值 (比如“MyApp.someController.property === ‘some value’”),那就應該把它加入到“Watched Expressions”中,這樣你就不用為了看它取的什麼值而在控制檯中一遍又一遍地輸入這個表示式了。
往下看就是“Call Stack(呼叫棧)”部分,它裡面顯示的是直到執行到當前程式碼位置為止系統中呼叫的每一個函式。在這個呼叫棧中,敲擊“CTRL + .”鍵可以往下走,“CTRL + ,”往上走。我在呼叫棧中上上下下翻來翻去一般都是為了檢視某個變數是怎麼取得它的當前值的,以及該變數在系統中的傳遞過程。
接下來的“Scope Variables(可訪問到的變數)”列出的是區域性變數和全域性變數。如果使用變數時用的是閉包,變數就會按照閉包進行分組顯示。“Global”組列出的是“window”物件所具有的變數(這個列表可長了去了)。隨著你不斷的切換當前函式,這個變數列表也會隨之自動更新。
既然你已經檢視完了斷點處你的應用的所有狀態,接下來你可能想再看看別處的情況。“Continue(繼續執行)”, “Step Over(單步跳過)”, “Step Into(單步進入)”以及“Step Out(單步跳出)”是你可以利用的幾個好按鈕。實際上,你使用它們的頻率會非常之高,所以最好還是再次開啟快捷鍵列表視窗,記住這幾個按鈕的快捷鍵。在這些列表中來來回回找東西用鍵盤可比用滑鼠效率高多了。如果你以前就用過偵錯程式,這些概念對你來說就不會陌生。但對於Web開發人員來講,這些概念他們還是第一次接觸。
“Continue”會繼續往下執行你的程式。如果執行過程中又再次遇到了這個斷點,程式執行依然會再次暫停在這裡。“Step over”將不對函式呼叫進行跟蹤執行,接下來還會繼續在當前函式之中單步執行。“Step into”在碰到新的函式呼叫時會跟蹤到函式裡進行單步執行。如果在同一行呼叫了多個函式,它會不斷按順序單步執行完一個函式再接著進入下一個函式進行執行。“Step Out”會執行完畢當前函式,回到呼叫棧之中上一層的函式進行單步執行。
在單步執行程式碼過程中定位bug或者找出程式碼的執行路線時。這幾個都是必不可少的工具。
還有一個非常順手的工具是在“XHR Breakpoints”部分。正如其名所示,它用來設定同XMLHttpReques物件相關的斷點。這是通過在你想檢視的URL中加入一個子字串來指定斷點的方法。非常好用!
還有,在“Scope Variables”部分,你可以右擊一個函式然後選擇“Jump to Definition”立即跳到定義該函式的檔案中定義該函式的那段程式碼。
時間線皮膚(Timeline Panel)
下一個要講的是時間線皮膚。你可以已經觀察到了, 每個皮膚都是用來除錯某一類的問題的。:元素( Elements)皮膚用於除錯DOM和CSS方面的問題的,資源(Resources)皮膚用於本地儲存和資原始檔,網路(Network)皮膚用於HTTP請求,指令碼(Scripts)皮膚用於Javascript。時間線(Timeline)皮膚用於除錯瀏覽器效能方面的問題。
我所說的“瀏覽器效能”是什麼意思?它所指的是一般都是不受你控制的東西,但它會影響你的應用的效能。對幕後發生的一切有所瞭解對開發日益複雜的應用來說,非常有必要。
時間線
首先要引起注意的是時間線部分。要啟用時間線,就要單擊“Record(記錄)”按鈕(在時間線皮膚的底端左邊部分的黑色圓圈)。等它變成紅色之後,就可以在你的應用中執行一個你想仔細觀察的任務。如果你想弄明白為什麼你的應用中滾動條滾動起來非常慢,你就可以慢慢滾動一下。如果你想弄清楚為什麼你應用中的模態皮膚(modal panel)裝載非常慢,那你就裝載一次。不要擔心你的動作涉及面太大後會導致時間線皮膚中顯示的東西過多,這有幾個工具能夠幫你解決這個問題。
現在你得到了你所關心的任務所產生的時間線,但你關心的其實是這些資料中的一小部分。想要“Zoom in(放大)”的話,你可以在時間線上部的圖形上單擊滑鼠後進行拖拽。然後你就能看到兩個調節線,通過拖拽調節線你可以調整下部可見內容的時間範圍。然後看下面的瀑布圖形,你會注意到有一些橘色的橫條壯膠囊圖形左邊有一個小箭頭。點選小箭頭可以展開其中的內容,包含的是觸發瀏覽器完成任務的函式呼叫。如下例所示,我們可以看到發生了一個滾動條scroll時間,呼叫了該時間的處理程式,從而產生了一個“Recalculate Style(重新計算顯示樣式)”事件。如果你把滑鼠懸停到側邊欄中的某項內容後,你就能看到更多的細節。
此時你可能會想知道,“那些佔用了時間的紫色事件是什麼意思?是重繪(Repaint)、重新計算顯示樣式(Recalculate Style)還是重新佈局(layout)?”。這些都是瀏覽器對可視內容發生改變做出回應時發生的瀏覽器事件。例如,如果你改變了可視區域的大小尺寸或者滾動了一下滾動條,瀏覽器就需要做大量的工作,才能保證讓所有一切看上去和你期待的情況相一致。你也可以在程式碼中自行呼叫這些事件,所以,花點時間對Inspector所顯示的這些東西有所瞭解還是值得的,不要對DOM發生的變化想當然。
Recalculate Style(重新計算顯示樣式)
這個事件會在你對CSS的屬性進行修改時發生。在上面的截圖中,你可以看到我兩次執行了同一條命令。第一次執行時,瀏覽器要進行Recalculate Style、Layout以及Paint。在第二次就只剩Recalculate style了。這是什麼情況?
因為這是一個剛剛載入的頁面,還處於完全不可見狀態,為一個未具style的div設定一個高度會導致該div中內容的佈局發生變化 (Layout), 從而導致視覺顯示上的變化 (Paint),最後就重新整理了它樣式(Recalculate Style)。第二次用同樣的值執行相同的命令時,瀏覽器跳過了Paint和Layout,因為它們根本沒有發生變化。注意這裡面的順序:Recalculate Style負責通知後繼過程是否需要得到觸發呼叫。
Repaint(重繪)
讓我們回到空白的頁面,然後給出div的寬度、高度和背景色,讓它在螢幕上顯示出真正的變化:
這次瀏覽器需要進行兩次重繪,但只需要計算一次佈局。這是因為在Recalculate Style這一步瀏覽器發現元素的位置/尺寸並沒有發生變化,但背景色變了,所以瀏覽器跳過了一次佈局計算。任何導致顯示內容變化的事件都會導致瀏覽器進行一次重繪。
Layout(佈局)
Layout常也稱為“Reflows(重新排版)”, 佈局事件會使瀏覽器重新計算頁面中個元素的位置。舉個例子,假如你讓一個圖片處於浮動(float)狀態,文字就會圍繞到它的周圍。如果你去除了float,瀏覽器就不得不對它周圍的文字進行重新排版(re-flow)。Paul Irish做了一個非常棒的視訊,描述了這種重新排版的情況並說明了如何避免這種情況發生。
Google啊,如果你在聽我說的話:請修復一下視窗大小變化後Inspector的行為吧!在Macbook Air小小的螢幕上,要是把Inspector和頁面並排放置到一起,就會經常碰到UI方面的很多bug。
要了解更多幕後發生的事情方面的細節內容,請參見這篇博文.
記憶體
現在看過了時間線並對你的應用進行了相應的優化,但你的應用在用過一段時間後還是會不時地出岔,有時執行緩慢,有時顯示內容時斷斷續續。在時間線中你也已經看到了有很多“GC” (記憶體垃圾回收的縮寫,GC會時不時的跑出來清理閒置的物件。) 事件發生,記憶體工具就是幫助你來解決這方面的問題的。
Tony Gentilcore寫了一篇很不錯的文章,介紹瞭如何查詢並修復記憶體洩露問題,這篇文章你一定要拜讀一下。下面我來簡單概述一下這篇文章。
在側邊欄單擊Memory,然後單擊“record”按鈕。此時就在你的應用中執行任務並觀察記憶體的變化情況。下圖所示是一個應用的記憶體簡況(profile)圖,該應用只是在每次發生滑鼠移動事件時生成一個物件並丟棄該物件。:
典型的JavaScript程式碼的記憶體圖樣子就像鋸齒:先是在GC執行前所佔記憶體不斷增加,然後GC就會適時回收閒置記憶體。在GC執行過幾輪後,記憶體圖就應該會比較平坦了。如果在每次GC執行的間隙圖形一直都是朝上高走,那麼這就是發生了記憶體洩漏。隨著你的應用不斷地吞噬越來越多的記憶體,其執行速度就會越來越慢,有的瀏覽器(MobileSafari)實際上會直接結束你的應用。
在圖形的下面顯示的是DOM節點和事件偵聽器呼叫總數,這些資料非常有用。這些資料的含義都相當的不言自明。
最後再說說,假如你在將應用部署到了生產環境(in production)後,發現裡面還有一個bug並在Inspector定位出了這個bug發生在哪裡。你如何把這一情況告訴你的同事或開發人員?其實,完全可以不用弄靜態的截圖,實際上你可以右擊“Timelines”和“Memory”,將你除錯過程儲存下來,這樣你就能夠將真正的除錯資料分享給別人了。這在團隊工作中方便極了。
Profiles(分析)皮膚
到現在為止,你開發的應用看上去和你想要的樣子很吻合,HTTP請求的總數也降到了最小,但應用中讓瀏覽器做了許多本不需要做的事。有些地方還不太對。所有的一切都是清清爽爽的,只有一個小地方不是這樣。你也已經用時間線皮膚對它進行除錯了,但還是沒有發現什麼有深度的細節性資訊。看來執行慢不是瀏覽器的過,而是你的程式碼。
此時就是該Profiles皮膚上場大顯身手的時候了。
JavaScript的CPU分析器(Profiler)
在分析皮膚中要做的第一類事情就是進行JS的CPU執行效率分析。這個描述高度概括了它的要測量的是什麼:你的應用中哪些函式的執行時間最長。
選中Profile皮膚後單擊“Start”按鈕。隨後你所作的動作都會被記錄下來,直到你按下那個鮮豔的紅色“Record”按鈕才會停止記錄(也可以單擊“Stop”按鈕)。一旦記錄停止,分析器就會按順序顯示出記錄期間所執行的所有函式以及每個函式執行所花的時間。你可能看到了列表頂端有個“(program)”這樣的一項內容。那是用來顯示WebKit幹活時所花的時間。你不能再進一步檢視它的內容了,而且對它也做不了什麼事情(但是在時間線標籤下應該可以幫你定位這方面的bug)。 除此之外,下圖所示是典型的Profile皮膚的樣子:
圖中所示是對我的部落格網站進行分析的結果,分析期間我開啟了相簿並多次開啟/關閉了幾張照片。 看起來這部分互動過程中最耗時的是設定curtain的透明度和getBoundingClientRect。要對應用的這部分互動過程進行優化,需要的正是這方面的資訊。
Google啊,如果你在聽我說的話:在這個皮膚,讓有用的資訊唾手可得,把無用的資訊挪到不礙眼的地方,要達此目的你需要做的事情還有很多。我經常會陷進一個無限深的列表,而且常常會碰到99.99%的時間花在了(Program)中的情況,這會完全會把別的函式的執行情況擠壓變形到意義盡失。
CSS選擇器分析器(CSS Selector Profiler)
使用CSS並不是沒有代價。複雜的樣式表從分析到計算再到最後應用,每一步都要花一些時間。CSS選擇器分析器顯示的是每個選擇器同DOM節點匹配的次數,以及瀏覽器應用這些選擇器時所花的時間。在具有很多同一型別div的比較複雜的應用中,對這些div應用樣式所花的時間在應用從調入瀏覽器到完成裝載的這段時間中佔的比例相當大。
Heap Snapshot(堆快照)
這個是Inspector中最不好用的檢視。不好用到我根本就沒發現它有什麼用處。看看這個例子:
據我所察,這個檢視裡有用資訊的量是零。 還得提一下Tony Gentilcore的這篇文章,也許它能點亮你前行之路。
Audits(審計)皮膚
馬上就要完工啦!最後要說的是Audits皮膚,它的作用基本上是在把應用部署到生產環境之前最後再給你一些效能方面的提醒。 實際上,它會對各種資源以及所有的HTTP請求進行檢查,根據業界當前的最佳實踐提出一些改進意見。例如,在我撰寫本文時,我執行了一下Audit皮膚,它告訴我,為了讓佈局過程能快一點完成,我應該在HTML裡指定圖片的大小。提醒得太好了!
文中所有的小技巧都有詳細的文件可看,你應該至少快速瀏覽一下那些文件。
結束語
我希望你已發現本文中至少有那麼一部分資訊能對你有用。迄今為止,我編寫複雜的桌面以及移動裝置Web應用有2年的時間了。為了解決各種不同型別的問題,我使用過本文所述的每一個皮膚。
如果我曲解了什麼、漏掉了什麼或者犯了什麼錯誤,懇請告知。
延伸閱讀
瀏覽器的工作原理 – 對Web應用執行根基中的執行過程和細節進行了非常棒的深入剖析。