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