调试第一步:让强大的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相关内容,是调试入门的第一步,更强大还在于谷歌的调试面板的灵活合理使用,更高级的还有自动化测试。


若是以为喜欢就❤❤❤一下吧!!!

相关文章
相关标签/搜索