?
本文檔使用 php中文網(wǎng)手冊 發(fā)布
瀏覽器實現(xiàn)
console對象的方法
log(),info(),debug()
warn(),error()
table()
count()
dir()
assert()
time(),timeEnd()
timeline(),timelineEnd(),timeStamp()
profile(),profileEnd()
group(),groupend(),groupCollapsed()
trace(),clear()
命令行API
debugger語句
移動端開發(fā)
模擬手機視口(viewport)
模擬touch事件
模擬經(jīng)緯度
遠(yuǎn)程除錯
Google Closure
Javascript 性能測試
第一種做法
第二種做法
參考鏈接
console對象是JavaScript的原生對象,它有點像Unix系統(tǒng)的標(biāo)準(zhǔn)輸出stdout和標(biāo)準(zhǔn)錯誤stderr,可以輸出各種信息用來調(diào)試程序,而且還提供了很多額外的方法,供開發(fā)者調(diào)用。它的常見用途有兩個。
顯示網(wǎng)頁代碼運行時的錯誤信息。
提供了一個命令行接口,用來與網(wǎng)頁代碼互動。
console對象的瀏覽器實現(xiàn),包含在瀏覽器自帶的開發(fā)工具之中。以Chrome瀏覽器的“開發(fā)者工具”(Developer Tools)為例,首先使用下面三種方法的一種打開它。
按F12或者Control+Shift+i(PC平臺)/ Alt+Command+i(Mac平臺)。
在菜單中選擇“工具/開發(fā)者工具”。
在一個頁面元素上,打開右鍵菜單,選擇其中的“Inspect Element”。
打開“開發(fā)者工具”以后,可以看到在頂端有八個面板卡可供選擇,分別是:
Elements:用來調(diào)試網(wǎng)頁的HTML源碼和CSS代碼。
Resources:查看網(wǎng)頁加載的各種資源文件(比如代碼文件、字體文件、css文件等),以及在硬盤上創(chuàng)建的各種內(nèi)容(比如本地緩存、Cookie、Local Storage等)。
Network:查看網(wǎng)頁的HTTP通信情況。
Sources:調(diào)試JavaScript代碼。
Timeline:查看各種網(wǎng)頁行為隨時間變化的情況。
Profiles:查看網(wǎng)頁的性能情況,比如CPU和內(nèi)存消耗。
Audits:提供網(wǎng)頁優(yōu)化的建議。
Console:用來運行JavaScript命令。
這八個面板都有各自的用途,以下內(nèi)容針對Console面板,又稱為控制臺。Console面板基本上就是一個命令行窗口,你可以在提示符下,鍵入各種命令。
下面介紹console對象提供的各種方法。
console.log方法用于在console窗口輸出信息。它可以接受多個參數(shù),將它們的結(jié)果連接起來輸出。
console.log("Hello World") // Hello World console.log("a","b","c") // a b c
console.log方法會自動在每次輸出的結(jié)尾,添加換行符。
console.log(1); console.log(2); console.log(3); // 1 // 2 // 3
如果第一個參數(shù)是格式字符串(使用了格式占位符),console.log方法將依次用后面的參數(shù)替換占位符,然后再進(jìn)行輸出。
console.log(" %s + %s = %s", 1, 1, 2) // 1 + 1 = 2
上面代碼中,console.log方法的第一個參數(shù)有三個占位符(%s),第二、三、四個參數(shù)會在顯示時,依次替換掉這個三個占位符。console.log方法支持的占位符有以下幾個,不同格式的數(shù)據(jù)必須使用對應(yīng)格式的占位符。
%s 字符串
%d 整數(shù)
%i 整數(shù)
%f 浮點數(shù)
%o 對象的鏈接
%c CSS格式字符串
var number = 11 * 9; var color = 'red'; console.log('%d %s balloons', number, color); // 99 red balloons
上面代碼中,第二個參數(shù)是數(shù)值,對應(yīng)的占位符是%d,第三個參數(shù)是字符串,對應(yīng)的占位符是%s。
使用%c占位符時,對應(yīng)的參數(shù)必須是CSS語句,用來對輸出內(nèi)容進(jìn)行CSS渲染。
console.log('%cThis text is styled!', 'color: #86CC00; background-color: blue; font-size: 20px; padding: 3px;' )
上面代碼運行后,輸出的內(nèi)容將顯示為藍(lán)底綠字。
log方法的兩種參數(shù)格式,可以結(jié)合在一起使用。
console.log(" %s + %s ", 1, 1, "= 2") // 1 + 1 = 2
如果參數(shù)是一個對象,console.log會顯示該對象的值。
console.log({foo: 'bar'}) // Object {foo: "bar"} console.log(Date) // function Date() { [native code] }
上面代碼輸出Date對象的值,結(jié)果為一個構(gòu)造函數(shù)。
console.info()和console.debug()都是console.log方法的別名,用法完全一樣。console.info方法會在輸出信息的前面,加上一個藍(lán)色圖標(biāo)。
console對象的所有方法,都可以被覆蓋。因此,可以按照自己的需要,定義console.log方法。
["log", "info", "warn", "error"].forEach(function(method) { console[method] = console[method].bind( console, new Date().toISOString() ); }); console.log("出錯了!"); // 2014-05-18T09:00.000Z 出錯了!
上面代碼表示,使用自定義的console.log方法,可以在顯示結(jié)果添加當(dāng)前時間。
warn方法和error方法也是輸出信息,它們與log方法的不同之處在于,warn方法輸出信息時,在最前面加一個黃色三角,表示警告;error方法輸出信息時,在最前面加一個紅色的叉,表示出錯,同時會顯示錯誤發(fā)生的堆棧。其他用法都一樣。
console.error("Error: %s (%i)", "Server is not responding",500) // Error: Server is not responding (500) console.warn('Warning! Too few nodes (%d)', document.childNodes.length) // Warning! Too few nodes (1)
本質(zhì)上,log方法是寫入標(biāo)準(zhǔn)輸出(stdout),warn方法和error方法是寫入標(biāo)準(zhǔn)錯誤(stderr)。
對于某些復(fù)合類型的數(shù)據(jù),console.table方法可以將其轉(zhuǎn)為表格顯示。
var languages = [ { name: "JavaScript", fileExtension: ".js" }, { name: "TypeScript", fileExtension: ".ts" }, { name: "CoffeeScript", fileExtension: ".coffee" } ]; console.table(languages);
上面代碼的language,轉(zhuǎn)為表格顯示如下。
(index) | name | fileExtension |
---|---|---|
0 | "JavaScript" | ".js" |
1 | "TypeScript" | ".ts" |
2 | "CoffeeScript" | ".coffee" |
復(fù)合型數(shù)據(jù)轉(zhuǎn)為表格顯示的條件是,必須擁有主鍵。對于上面的數(shù)組來說,主鍵就是數(shù)字鍵。對于對象來說,主鍵就是它的最外層鍵。
var languages = { csharp: { name: "C#", paradigm: "object-oriented" }, fsharp: { name: "F#", paradigm: "functional" } }; console.table(languages);
上面代碼的language,轉(zhuǎn)為表格顯示如下。
(index) | name | paradigm |
---|---|---|
csharp | "C#" | "object-oriented" |
fsharp | "F#" | "functional" |
count方法用于計數(shù),輸出它被調(diào)用了多少次。
function greet(user) { console.count(); return "hi " + user; } greet('bob') // : 1 // "hi bob" greet('alice') // : 2 // "hi alice" greet('bob') // : 3 // "hi bob"
上面代碼每次調(diào)用greet函數(shù),內(nèi)部的console.count方法就輸出執(zhí)行次數(shù)。
該方法可以接受一個字符串作為參數(shù),作為標(biāo)簽,對執(zhí)行次數(shù)進(jìn)行分類。
function greet(user) { console.count(user); return "hi " + user; } greet('bob') // bob: 1 // "hi bob" greet('alice') // alice: 1 // "hi alice" greet('bob') // bob: 2 // "hi bob"
上面代碼根據(jù)參數(shù)的不同,顯示bob執(zhí)行了兩次,alice執(zhí)行了一次。
dir方法用來對一個對象進(jìn)行檢查(inspect),并以易于閱讀和打印的格式顯示。
console.log({f1: 'foo', f2: 'bar'}) // Object {f1: "foo", f2: "bar"} console.dir({f1: 'foo', f2: 'bar'}) // Object // f1: "foo" // f2: "bar" // __proto__: Object
上面代碼顯示dir方法的輸出結(jié)果,比log方法更易讀,信息也更豐富。
該方法對于輸出DOM對象非常有用,因為會顯示DOM對象的所有屬性。
console.dir(document.body)
assert方法接受兩個參數(shù),第一個參數(shù)是表達(dá)式,第二個參數(shù)是字符串。只有當(dāng)?shù)谝粋€參數(shù)為false,才會輸出第二個參數(shù),否則不會有任何結(jié)果。
// 實例 console.assert(true === false, "判斷條件不成立") // Assertion failed: 判斷條件不成立
下面是另一個例子,判斷子節(jié)點的個數(shù)是否大于等于500。
console.assert(list.childNodes.length < 500, "節(jié)點個數(shù)大于等于500")
這兩個方法用于計時,可以算出一個操作所花費的準(zhǔn)確時間。
console.time("Array initialize"); var array= new Array(1000000); for (var i = array.length - 1; i >= 0; i--) { array[i] = new Object(); }; console.timeEnd("Array initialize"); // Array initialize: 1914.481ms
time方法表示計時開始,timeEnd方法表示計時結(jié)束。它們的參數(shù)是計時器的名稱。調(diào)用timeEnd方法之后,console窗口會顯示“計時器名稱: 所耗費的時間”。
console.timeline和console.timelineEnd這兩個方法用于定義一個新的時間線,可以在Timeline面板查看。這兩個方法只有Chrome開發(fā)者工具支持。
console.timeline('Google Search'); // Do some work console.timelineEnd('Google Search');
上面代碼定義了一個名稱叫做“Google Search”的時間線,在這個時間線里的所有事件的耗時,可以在Timeline面板中查看。
console.timeStamp方法用在上面兩個方法的中間,用于為時間線添加一個時間戳。時間戳的名字就是timeStamp方法的參數(shù)。
console.profile方法用來新建一個性能測試器(profile),它的參數(shù)是性能測試器的名字。
console.profile('p') // Profile 'p' started.
console.profileEnd方法用來結(jié)束正在運行的性能測試器。
console.profileEnd() // Profile 'p' finished.
打開瀏覽器的開發(fā)者工具,在profile面板中,可以看到這個性能調(diào)試器的運行結(jié)果。
console.group和console.groupend這兩個方法用于將顯示的信息分組。它只在輸出大量信息時有用,分在一組的信息,可以用鼠標(biāo)折疊/展開。
console.group('Group One'); console.group('Group Two'); // some code console.groupEnd(); // Group Two 結(jié)束 console.groupEnd(); // Group One 結(jié)束
console.groupCollapsed方法與console.group方法很類似,唯一的區(qū)別是該組的內(nèi)容,在第一次顯示時是收起的(collapsed),而不是展開的。
console.groupCollapsed('Fetching Data'); console.log('Request Sent'); console.error('Error: Server not responding (500)'); console.groupEnd();
上面代碼只顯示一行”Fetching Data“,點擊后才會展開,顯示其中包含的兩行。
console.trace方法顯示當(dāng)前執(zhí)行的代碼在堆棧中的調(diào)用路徑。
console.trace() // console.trace() // (anonymous function) // InjectedScript._evaluateOn // InjectedScript._evaluateAndWrap // InjectedScript.evaluate
console.clear方法用于清除當(dāng)前控制臺的所有輸出,將光標(biāo)回置到第一行。
在控制臺中,除了使用console對象,還可以使用一些控制臺自帶的命令行方法。
(1)$_
$_屬性返回上一個表達(dá)式的值。
2+2 // 4 $_ // 4
(2)$0 - $4
控制臺保存了最近5個在Elements面板選中的DOM元素,$0代表倒數(shù)第一個,$1代表倒數(shù)第二個,以此類推直到$4。
(3)$(selector)
$(selector)返回一個數(shù)組,包括特定的CSS選擇器匹配的所有DOM元素。該方法實際上是document.querySelectorAll方法的別名。
var images = $('img'); for (each in images) { console.log(images[each].src); }
上面代碼打印出網(wǎng)頁中所有img元素的src屬性。
(4)$$(selector)
$$(selector)返回一個選中的DOM對象,等同于document.querySelectorAll。
(5)$x(path)
$x(path)方法返回一個數(shù)組,包含匹配特定XPath表達(dá)式的所有DOM元素。
$x("//p[a]")
上面代碼返回所有包含a元素的p元素。
(6)inspect(object)
inspect(object)方法打開相關(guān)面板,并選中相應(yīng)的元素:DOM元素在Elements面板中顯示,JavaScript對象在Profiles中顯示。
(7)getEventListeners(object)
getEventListeners(object)方法返回一個對象,該對象的成員為登記了回調(diào)函數(shù)的各種事件(比如click或keydown),每個事件對應(yīng)一個數(shù)組,數(shù)組的成員為該事件的回調(diào)函數(shù)。
(8)keys(object),values(object)
keys(object)方法返回一個數(shù)組,包含特定對象的所有鍵名。
values(object)方法返回一個數(shù)組,包含特定對象的所有鍵值。
var o = {'p1':'a', 'p2':'b'}; keys(o) // ["p1", "p2"] values(o) // ["a", "b"]
(9)monitorEvents(object[, events]) ,unmonitorEvents(object[, events])
monitorEvents(object[, events])方法監(jiān)聽特定對象上發(fā)生的特定事件。當(dāng)這種情況發(fā)生時,會返回一個Event對象,包含該事件的相關(guān)信息。unmonitorEvents方法用于停止監(jiān)聽。
monitorEvents(window, "resize"); monitorEvents(window, ["resize", "scroll"])
上面代碼分別表示單個事件和多個事件的監(jiān)聽方法。
monitorEvents($0, "mouse"); unmonitorEvents($0, "mousemove");
上面代碼表示如何停止監(jiān)聽。
monitorEvents允許監(jiān)聽同一大類的事件。所有事件可以分成四個大類。
mouse:"mousedown", "mouseup", "click", "dblclick", "mousemove", "mouseover", "mouseout", "mousewheel"
key:"keydown", "keyup", "keypress", "textInput"
touch:"touchstart", "touchmove", "touchend", "touchcancel"
control:"resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"
monitorEvents($("#msg"), "key");
上面代碼表示監(jiān)聽所有key大類的事件。
(10)profile([name]),profileEnd()
profile方法用于啟動一個特定名稱的CPU性能測試,profileEnd方法用于結(jié)束該性能測試。
profile("My profile") profileEnd("My profile")
(11)其他方法
命令行API還提供以下方法。
clear()方法清除控制臺的歷史。
copy(object)方法復(fù)制特定DOM元素到剪貼板。
dir(object)方法顯示特定對象的所有屬性,是console.dir方法的別名。
dirxml(object)方法顯示特定對象的XML形式,是console.dirxml方法的別名。
debugger語句必須與除錯工具配合使用,如果沒有除錯工具,debugger語句不會產(chǎn)生任何結(jié)果。
在chrome瀏覽器中,當(dāng)代碼運行到debugger指定的行時,就會暫停運行,自動打開console界面。它的作用類似于設(shè)置斷點。
for(var i = 0;i<5;i++){ console.log(i); if (i===2) debugger; }
上面代碼打印出0,1,2以后,就會暫停,自動打開console窗口,等待進(jìn)一步處理。
(本節(jié)暫存此處)
chrome瀏覽器的開發(fā)者工具,提供一個選項,可以模擬手機屏幕的顯示效果。
打開“設(shè)置”的Overrides面板,選擇相應(yīng)的User Agent和Device Metrics選項。
User Agent可以使得當(dāng)前瀏覽器發(fā)出手機瀏覽器的Agent字符串,Device Metrics則使得當(dāng)前瀏覽器的視口變?yōu)槭謾C的視口大小。這兩個選項可以獨立選擇,不一定同時選中。
我們可以在PC端模擬JavaScript的touch事件。
首先,打開chrome瀏覽器的開發(fā)者工具,選擇“設(shè)置”中的Overrides面板,勾選“Enable touch events”選項。
然后,鼠標(biāo)就會觸發(fā)touchstart、touchmove和touchend事件。(此時,鼠標(biāo)本身的事件依然有效。)
至于多點觸摸,必須要有支持這個功能的設(shè)備才能模擬,具體可以參考Multi-touch web development。
chrome瀏覽器的開發(fā)者工具,還可以模擬當(dāng)前的經(jīng)緯度數(shù)據(jù)。打開“設(shè)置”的Overrides面板,選中Override Geolocation選項,并填入相應(yīng)經(jīng)度和緯度數(shù)據(jù)。
(1) Chrome for Android
Android設(shè)備上的Chrome瀏覽器支持USB除錯。PC端需要安裝Android SDK和Chrome瀏覽器,然后用usb線將手機和PC連起來,可參考官方文檔。
(2) Opera
Opera瀏覽器的除錯環(huán)境Dragonfly支持遠(yuǎn)程除錯(教程)。
(3) Firefox for Android
參考官方文檔。
(4) Safari on iOS6
你可以使用Mac桌面電腦的Safari 6瀏覽器,進(jìn)行遠(yuǎn)程除錯(教程)。
(本節(jié)暫存此處)
Google Closure是Google提供的一個JavaScript源碼處理工具,主要用于壓縮和合并多個JavaScript腳本文件。
Google Closure使用Java語言開發(fā),使用之前必須先安裝Java。然后,前往官方網(wǎng)站進(jìn)行下載,這里我們主要使用其中的編譯器(compiler)。
首先,查看使用幫助。
java -jar /path/to/closure/compiler.jar --help
直接在腳本命令后面跟上要合并的腳本,就能完成合并。
java -jar /path/to/closure/compiler.jar *.js
使用--js參數(shù),可以確保按照參數(shù)的先后次序合并文件。
java -jar /path/to/closure/compiler.jar --js script1.js --js script2.js --js script3.js
但是,這樣的運行結(jié)果是將合并后的文件全部輸出到屏幕(標(biāo)準(zhǔn)輸出),因此需要使用--js_output_file參數(shù),指定合并后的文件名。
java -jar /path/to/closure/compiler.jar --js script1.js --js script2.js --js script3.js --js_output_file scripts-compiled.js
(本節(jié)暫存此處)
最常見的測試性能的做法,就是同一操作重復(fù)n次,然后計算每次操作的平均時間。
var totalTime, start = new Date, iterations = 6; while (iterations--) { // Code snippet goes here } // totalTime → the number of milliseconds it took to execute // the code snippet 6 times totalTime = new Date - start;
上面代碼的問題在于,由于計算機的性能不斷提高,如果只重復(fù)6次,很可能得到0毫秒的結(jié)果,即不到1毫秒,Javascript引擎無法測量。
另一種思路是,測試單位時間內(nèi)完成了多少次操作。
var hz, period, startTime = new Date, runs = 0; do { // Code snippet goes here runs++; totalTime = new Date - startTime; } while (totalTime < 1000); // convert ms to seconds totalTime /= 1000; // period → how long per operation period = totalTime / runs; // hz → the number of operations per second hz = 1 / period; // can be shortened to // hz = (runs * 1000) / totalTime;
這種做法的注意之處在于,測試結(jié)構(gòu)受外界環(huán)境影響很大,為了得到正確結(jié)構(gòu),必須重復(fù)多次。
Chrome Developer Tools, Using the Console
Matt West, Mastering The Developer Tools Console
Firebug Wiki, Console API
Axel Rauschmayer, The JavaScript console API
Marius Schulz, Advanced JavaScript Debugging with console.table()
Google Developer, Command Line API Reference