調試第一步:讓強大的console家族助你一臂之力

console相比你們必定不陌生,平時項目中用的最多的就是console.log()方法吧。可是console相關的方法有不少,涉及的調試面板的相關內容比較普遍,完全弄清楚它們並在項目中合理使用,有助於咱們更好的開發和調試。javascript

下面咱們在控制檯打印一下console,看看它還有哪些神奇的方法:php

若是沒了解過console的,似不似驚呆了,console還有這麼多方法?下面咱們從最簡單的console.log方法開始,逐個分析其餘方法以及所涉及到的調試技巧。css

1.console.log()打印內容。這個方法那是太熟悉不過了,平時也是用的最多的或許也是這一個吧!!!基本用法呢就不說了,主要聊一聊console.log()的佔位符。其共有五種佔位符,分別是:

  1. %s 字符串
  2. %d 或 %i 整數
  3. %f 浮點數
  4. %o 對象的連接
  5. %c CSS格式字符串

若是方法的第一個參數中使用了佔位符,那麼就依次使用後面的參數進行替換。
html

const name = 'chinaBerg';
const age = 88;
const money = 12.88;
const obj = {
    status: '很積極'
}

console.log('我叫%s,%d歲,有%f元,狀態:%o', name, age, money, obj.status, '又打印一句話')複製代碼

谷歌打印結果:前端


能夠看到咱們後面使用的參數對前面的佔位符進行了替換,有點像咱們字符串拼接的簡化操做。好比咱們es5中的字符串拼接:java

console.log('我叫' +  name + ' ,' + age +'歲,有' + money + '元')複製代碼

固然了,es6已經有了更強悍的字符串模板:node

console.log(`我叫${name}${age}歲, 有${money}元`);複製代碼

拼接的字符串中混着使用也是能夠的:css3

//例如,這裏演示的:第一參數是拼接的字符串,第二參數插入字符串的浮點數
console.log('我叫' +  name + ' ,' + age +'歲,有%f元',  money)複製代碼

但es6的字符串模板中,只能使用%c佔位符,其餘佔位符是沒有效果的。es6

// 注意這裏字符串模板的最後插入了%f
console.log(`我叫${name}${age}歲, 有%f元`, 12.88);複製代碼


%c佔位符仍是略有趣味的:json

const css1 = 'font-size: 22px;font-weight: bold';
const css2 = 'border: 1px solid green';
const css3 = 'color: #fff;background: #f00';

// 佔位符填入				
console.log('%c %s + %s = %s', css1, 1, 2, 3);
// 字符串拼接形式中插入%c佔位符
console.log('%c個人名字叫' + name + ', 今年' + age + '歲', css2);
// es6字符串模板中插入%c佔位符
console.log(`%c我叫${name}${age}歲, 有%f元`, css3);
複製代碼

谷歌打印效果:


能夠看到這些打印的內容已經被添加了咱們的樣式。

---------------------------------------------------------------------

2.可是和console.log()很像的還有倆,一個是console.info(),一個是console.debug()。其實這個三個功能都是同樣的,只不過有些區別,下面就具體介紹一下這三個方法。

先來看一下下面這三行代碼,在谷歌、火狐、ie上的打印效果:

console.log('我是console.log()打印出來的');

console.info('我是console.info()打印出來的');

console.debug('console.debug()打印出來的')複製代碼
谷歌瀏覽器控制檯打印效果:

火狐控制檯:


ie控制檯:


從結果能夠看出:

  • console.log()方法,不管哪一個瀏覽器,打印出的效果都是同樣的。
  • console.info()方法,ie沒有打印出來,即不支持這個屬性。可是在谷歌和火狐上又略有區別:打印的結果是同樣的,可是火狐控制檯上,會在打印的結果前面添加一個相似i的小符號。
  • console.debug()方法,谷歌和opera是不支持的,ie和火狐是支持的。

因此呢,既然三個方法功能是基本同樣的,咱們若是隻想打印一些內容的話,仍是老老實實的使用console.log()穩一點。固然了,這也抵不住你就使用火狐來debug呢!但是,考慮到若是你的代碼庫的某些打印信息須要給別的開發者看的話,仍是用兼容性更好的穩一些。

---------------------------------------------------------------------

3.console.clear() 清除控制檯打印的內容,並將光標迴歸到第一行。


這個屬性沒什麼好說的,和咱們點擊控制檯的這個清除按鈕的效果同樣。

---------------------------------------------------------------------

4. console.assert(表達式 [,arg1, arg2……argn])打印斷言。

第一個參數是用來判斷是否打印斷言的表達式,只有當表達式的值爲falsy的時候,纔會打印後續的參數:

const arr = [1, 2, 3];

// 打印斷言,若是arr[0]的值不等於2,則打印提示信息
console.assert(arr[0] === 2, 'arr[0]的值不等於2');複製代碼

谷歌控制檯打印以下:


若是沒有參數,默認打印以下字符串:

其餘注意點:
  • 客戶端的console.assert()打印斷言,並不會阻塞後續代碼的執行,只是在斷言的表達式爲false的時候,向控制檯打印你的內容。
  • 而在node.js中,值爲假的斷言將會致使一個AssertionError被拋出,使得代碼執行被打斷。這二者是有區別的。

---------------------------------------------------------------------

5.console.count() 打印計數。輸出他被調用了多少次。

傳遞一個參數做爲計數提示:

for (let i = 0; i < 10; i++) {
    console.count('我被調用了');
}複製代碼

谷歌控制檯:


簡單修改一下:

for (let i = 0; i < 10; i++) {
    console.count(`我是${i}我被調用了`);
}複製代碼

打印效果:


這個方法意思就是:向控制檯寫入在同一行使用相同標籤調用 count() 的次數。

就是若是你給count()傳遞的參數值不同,那麼是分開計數的。

再看一個簡單的示例:

function fun (name) {
    console.count(name)
}
fun('小米');
fun('小剛');
fun('小米');複製代碼

效果:


因此,即使同一個函數,咱們能夠清晰的知道小米同窗被調用了2次,小剛同窗被調用了1次。

若是不傳遞參數,默認的計數提示標籤是default字符串:

for (let i = 0; i < 10; i++) {
    // count()沒傳遞提示標籤
    console.count();
}複製代碼

效果以下:


通常在某些循環中,若是咱們想知道一個函數或者變量被執行或者調用了多少次的時候,可使用console.count()方法,而經過傳遞提示標籤,咱們更能夠清晰的知道一個函數分別被不一樣的狀況調用了幾回,從而幫助咱們定位錯誤信息。

---------------------------------------------------------------------

6.console.time()和console.timeEnd()打印計時。用來跟蹤某一個操做的佔用時長。每個計時器必須擁有惟一的名字,time()的參數名和timeEnd()的參數名要同樣。能夠沒有參數,默認計時提示爲default:

// 當即啓動計時器
console.time()

// 某些操做
for (let i = 0; i < 10000; i++) {
    // 某些操做				
}

// 當即結束計時器,並輸出計時結果
console.timeEnd()複製代碼

控制檯打印效果以下:


傳遞計時器提示:

// 當即啓動計時器
console.time('time')

// 某些操做
for (let i = 0; i < 10000; i++) {
    // 某些操做				
}

// 當即結束計時器,並輸出計時結果
console.timeEnd('time')複製代碼

控制檯打印效果以下:


注意:

  • 頁面中最多能同時運行10,000個計時器
  • 該方法並不會將結算結果返回到js中,而只是能打印在控制檯上。因此不能使用此方法在js中來做爲普通計時器使用或者進行性能收集器的一部分。


7.console.dir() 輸出以 JavaScript 形式表示的指定對象。若是正在記錄的對象是 HTML 元素,將輸出其以 DOM 形式表示的屬性。

打印一個對象:

// 一個對象
const obj = {
    name: '某某渣',
    age: 22,
    sex: '男'
}

// dir打印
console.dir(obj);

// log打印
console.log(obj);複製代碼

谷歌控制檯效果:


對於對象或者json等,console.log()和console.dir()效果基本同樣。

可是若是打印的是一個dom元素:

// dir打印
console.dir(document.body);

// log打印
console.log(document.body)複製代碼
  • console.dir()會將dom的全部屬性和事件都被打印出來:
  • console.log()打印的就是dom:

若是哪天你coding的時候忽然想不起來dom的某個方法了,你徹底能夠console.dir()一下,而沒必要去翻閱資料了。

---------------------------------------------------------------------

8.console.dirxml(object) 若是能夠,輸出 object 子級元素的 XML 表示形式,不然輸出其 JavaScript 表示形式。 在 HTML 和 XML 元素上調用 console.dirxml() 等同於調用 console.log()。

---------------------------------------------------------------------

9.console.group() + console.groupEnd()將控制檯輸出的內容進行分組。

將打印的信息歸類分組打印,而且能夠展開、摺疊。這在輸出大量數據的或許有用。

// console.groupCollapsed() + console.groupEnd()的形式,默認是摺疊的
console.group('分第一組');
console.log('html')
console.dir({ type: '前端'}),
console.groupEnd('分第一組')

// console.group() + console.groupEnd() 默認是展開的
console.group('分第2組');
console.log('php')
console.dir({ type: '後臺'}),
console.groupEnd('分第2組')複製代碼

谷歌打印效果:


---------------------------------------------------------------------

10.console.table()能夠將數組、對象等複雜類型的數據打印成表格的形式。

打印簡單的數組:

const arr = ['a', 'b'];
			
console.table(arr)複製代碼

打印複雜的數組:

const arr = [
    {
        name: '小明',
        age: 22,
        likes: ['跳舞', '上網']
    },
    {
        name: '小剛',
        age: 23,
        likes: ['擼碼', '計算機']
    }
];
				
console.table(arr)複製代碼


打印對象:

const obj = {
    name: '小明',
    age: 22,
    likes: [
        {
            a: 1,
            b: 2
        },
        {
            a: 3,
            b: 4
        },
    ]
}
				
console.table(obj)複製代碼


經過console.table()打印出的結果,咱們能夠很直觀的看到數據的組成。

---------------------------------------------------------------------

11.console.trace()堆棧中調用此方法的路徑。

若是想要清楚地知道一個函數的調用軌跡,能夠將此方法寫在函數內部,即可以跟蹤函數的調用軌跡,代碼實現以下:

function test(name) {
    console.trace(`此處調用了${name}`)
}
				
function doSome (name) {
    test(name);
}
				
doSome('翠花');複製代碼

谷歌控制檯打印以下:


此處打印出了js中調用test()的全部堆棧位置。從上到下依次爲最裏層的調用一直到最外層調用。平時咱們使用第三方庫的時候,若是寫法不對,常常能夠在控制檯看到咱們的報錯信息,而且像這樣打印出了錯誤位置的堆棧信息。

---------------------------------------------------------------------

12.console.warn()打印一條警告信息

console.warn('我是一條警告')複製代碼

谷歌打印結果以下:


打印結果會有一條黃色背景,前面附加一個感嘆號的圖標。

默認是收起的,點擊能夠展開,列出了警告位置的堆棧信息,點擊堆棧位置能夠對應打開警告位置代碼。這個的使用沒什麼好說的,若是你須要打印一條警告信息,用這個方法很合適。

---------------------------------------------------------------------

13.console.error()打印錯誤。

console.error('我這裏出現了錯誤,我來告知用戶')
複製代碼

谷歌打印結果以下:

該方法主要用來打印錯誤,打印結果的樣式如上圖。也沒什麼好說的,不過若是你開發第三方庫的時候,能夠用到。可是throw拋出錯誤的方式也會用到很多。

---------------------------------------------------------------------

14.console.profile() 和 console.profileEnd() 新建一個性能分析器(基於cpu的使用狀況)。用於函數性能分析的利器。

咱們已經知道經過console.time()和console.timeEnd()咱們能夠知道一段代碼的運行時間。可是,若是咱們須要分析較爲複雜的js邏輯代碼,繼而從中找出程序運行的性能瓶頸的話,若是繼續使用console.time()方法的話,意味着咱們要插入大量的該方法,這顯然是笨拙的,也是讓咱們不可接受的。

相對於複雜邏輯的JavaScript程序調優,console.profile() 和 console.profileEnd()新建性能分析器便派上用場了。

用法和time的同樣,console.profile()開始,console.profileEnd()結束,須要傳遞一個參數做爲標籤使用,說俗了點就是爲這個性能分析器起個名字。看下以下代碼,咱們測試幾種不一樣for循環書寫方式的耗時狀況:

// 簡單新建一個數組吧,新建一個一千萬個成員爲1的數組
let arr = new Array(10000000).fill(1);
				
// 第一種for循環書寫方式				
function fun1 () {
    for (let i = 0, len = arr.length; i < len; i++) {}
}

// 第二種for循環書寫方式				
function fun2 () {
    for (let i = arr.length; i --; ) {}
    fun1();
}

// 第三種for循環書寫方式		
function fun3 () {
    for (let i = 0, item; item = arr[i++]; ) {}
}

// 執行三個函數		
function fun () {
    fun1();
    fun2();
    fun3();
}

// 當即開始一個性能分析器
console.profile('測試for循環');
fun();
//
console.profileEnd('測試for循環');
複製代碼

運行如上程序,打開谷歌控制檯一看:

嗯,沒錯,打印了兩句話,性能分析器開啓和結束。納尼~說的性能分析器呢???小拳拳要捶你胸口了!!!

別急,性能分析器不在這裏,在javascript Profiler面板中。


點擊javascript Profiler面板,即可以看到性能分析器。若是你沒有上面紅框標識的面板,那麼點擊右邊的三個點,在下拉菜單中依次選擇More tools -> JavaScript Profiler選項,就能夠將該選項添加到上面的紅框位置。而後點擊該面板,進入對應內容:

能夠看到,已經有了剛纔的性能分析狀況,這裏清晰展現了每個函數執行過程所耗時間。而後咱們點開每個函數看下具體的狀況:

圖上我進行了標註:

  • 1處,Self Time表示當前函數自身運行耗時,什麼意思?就是說當前函數自身執行耗時,不包括當前函數中調用的其餘函數運行耗時。
  • 2處,Total Time表示當前函數運行總耗時,包括了自身運行耗時+函數內部調用的其餘函數的執行耗時。
  • Function那一列,咱們經過上圖打開的fun1那一欄說明,fun1展開後的結果包括funfun2,這指的是函數fun1在函數funfun2中被調用執行的耗時。經過代碼咱們知道,fun1函數確實在fun函數和fun2個被調用過1次,因此這裏展現了fun在這兩處被調用執行的耗時時間。
  • 每一個函數行最右邊還有會堆棧位置,點擊便可進入resouce面板中該函數所在的文件位置。

若是你關注fun1函數的執行時間,你能夠點擊選中fun1這一行,而後點擊上面的眼睛圖標,將自動只爲你展示fun1函數的信息:


  • 選中函數行,點擊眼睛即針對性的展現當前函數。
  • 選中函數和,若是點擊×號,將會刪除當前函數行。
  • 選中函數行點擊眼睛進入後,若是想返回到上述所有函數行的面板,能夠點擊上圖刷新按鈕。或者刪除了函數行後也能夠恢復如上圖。
  • 上圖三個按鈕只有在顏色變深的時候纔可點擊,眼睛和×號只有在選中函數行的狀況下可點,刷新按鈕在進入或者刪除函數行以後能夠點。

還有一點沒介紹,就是該這種數據展現方式,是默認的方式:Heavy(Bottom Up),即將全部執行的函數,按照耗時長度,從上到降低序排列,耗時的在最上面,不耗時的在最下面。可是他還有另外兩種方式(Chart 和 Tree),以下圖:


咱們先來講說Tree型數據分析,下面咱們先切換到Tree型看下圖:

將每一個函數行打開後,顯示了該函數所調用的函數。這種數據分析的展現方式實際上是,先展現最外層的函數,展開後,顯示該函數所調用的全部函數,依次往裏類推。每一行都展現該函數執行的耗時。其餘操做同上。

最後說一下Chart的方式,Chart是以圖片給咱們展現函數運行後性能,能夠看到每一個函數開始運行的時間節點,以下圖:

大體分爲上下兩部分,上部分藍色區域爲cpu佔用的大致走勢圖,能夠清晰地看到每一個時間節點的cpu佔用狀況,是高是滴一目瞭然。下半部分爲每一個函數開始運行的時間節點。

若是點擊上部分藍色區域,還能夠更細粒度查看當前事件的函數運行狀況(在當前時間節點劃分爲更細的力度),以下圖:


鼠標移入某個函數,還能夠看到當前函數所運行的耗時狀況,以下圖:


console.profile() 和 console.profileEnd()函數性能分析器的創建,給咱們分析函數性能帶來的很是大的便利,這對於咱們檢測程序運行瓶頸很是有幫助。 谷歌爲咱們開發這麼好使的調試工具,必定要在須要的時候好好利用。

---------------------------------------------------------------------

15.console.timeStamp('事件信息'),在Performance(之前叫Timeline)性能面板中的會話錄製期間插入一條添加一個事件。

說到這個console.timeStamp()方法,這個方法在咱們進行性能調試的時候會用到。說到這個方法首先要提到Performance性能面板,由於該方法打印出來的結果須要在這個調試面板中查看,準確的來講,該方法是配合性能面板來調試的:


如上圖,在Perdormance面板中,咱們能夠分析當前頁面的性能,能夠得知頁面加載和用戶交互相關的事件分析結果。關於Performance這塊的內容,若是仔細提及來,內容是比較多的。這裏暫且只介紹和console.timeStamp方法相關的內容。之後能夠單獨把這塊拿出來細細分析和記錄。

迴歸正題,console.timeStamp能夠在時間軸上寫入一個事件:

// 一些其餘操做
for (let i = 0; i < 10000; i ++) {}

// 在錄製會話期間插入的第一個事件		
console.timeStamp('第一個循環完了')
				
// 一些其餘操做
for (let i = 0; i < 10000; i ++) {}
				
// 在錄製會話起價插入的第二個事件
console.timeStamp('第2個循環完了')複製代碼

錄製完會話後,咱們輸入移入下圖紅框左上方的黃色豎線上能夠看到彈出一個提示框,上面標註了Timestamp提示:‘第一個循環完了’,而且還有該事件插入時的時間節點。


---------------------------------------------------------------------

16.console.markTimeline()方法效果等同於console.timeStamp(),是console.timeStamp()之前的寫法,已經淘汰了。很少說。

---------------------------------------------------------------------

17.console.timeLine('標籤參數')配合 console.timeLineEnd('標籤參數')錄製一段時間的時間軸。

咱們在上面的console.timeStamp方法中瞭解到,在Performance面板中,咱們能夠錄製當前頁面的會話信息,而經過console.timeline和console.timelineEnd能夠只錄制某一段時間的會話信息。

// 錄製第一段時間的會話信息
console.timeline('測試循環100萬相關的性能分析')
for (let i = 0; i < 1000000; i ++) {}
console.timelineEnd('測試循環100萬相關的性能分析')


// 錄製第二段時間的會話信息				
console.timeline('測試循環1000萬相關的性能分析')
for (let i = 0; i < 10000000; i ++) {}
console.timelineEnd('測試循環1000萬相關的性能分析')複製代碼

在咱們的Performance面板中,點擊開始錄製當前頁面,而後查看錄製後的結果:


console.timeline('參數標籤')console.timelineEnd('參數標籤'),兩個方法須要接收相同的一個參數標籤,就是一個標識而已。

這裏會了這個用法以後,更多的是怎樣在Performance中進行性能的分析,而後找出影響程序性能的瓶頸,這纔是重要的。


弄清楚了強大了console家族,能夠在開發調試過程當中祝咱們一臂之力。簡單的運用console相關內容,是調試入門的第一步,更強大還在於谷歌的調試面板的靈活合理使用,更高級的還有自動化測試。


若是以爲喜歡就❤❤❤一下吧!!!

相關文章
相關標籤/搜索