静态检查
关于javascript的语言特性,Douglas Crockford在蝴蝶书里面写过:“一些特性因为规范的不完善而可能导致可移植性问题,一些特性会导致代码难以阅读或修改,一些特性诱使我们追求奇技淫巧但却易于出错,还有一些是语言本身设计错误”。
由于javascript语言本身弱类型灵活多变的特点,某些特性的不正确使用或者格式的混乱会导致造成一些未预见的行为或错误。为了解决此类的问题,我们需要静态检查。
JSLint
JSLint是Douglas Crockford编写的工具,它将Web开发人员多年积累下来的反模式整合为一套规则,用以对Javascript脚本扫描,并给出相应的问题描述信息。
规则大致包含几个方面:
- 语法错误检查: 比如括号配对遗漏等问题。
- 代码格式检查: 比如缺少结尾分号、数组&对象末尾多余逗号等问题。
- 变量定义检查: 比如未定义变量成为全局变量等问题。
- 糟粕特性检查: 比如with、void语句等不推荐使用的问题。
最初的JSLint由于规则严格不妥协和拒绝开源等问题,受到一些诟病。时至今日JSLint也允许规则自定义并且可以在github上获取到它了。
关于JSLint的默认规则和自定义规则盗张图描述:
另外,在这篇文章发布的三天前(2015/10/22), Douglas依旧在更新JSLint。它的强(yan)大(ge)功(gui)能(ze)从源码中可以略见一斑。
JSLint https://github.com/douglascrockford/JSLint
JSHint
JSHint是Anton Kovalyov基于JSLint实现的一个开源工具。相对于JSLint来说,JSHint稍微友好一些,可配置性更高。也是现在web开发者使用最多的静态检查工具之一。
关于JSHint配置,分 增强参数(Enforcing Options) 和 松弛参数(Relaxing Options) 。将增强参数设置为true,则JSHint会检查规则更严格,在某些情况下会产生更多告警;同理,将松弛参数设置为true,则JSHint会检查规则更友好,在某些情况下会产生的告警更少。
记录一部分常用配置参数:
增强参数 | 作用 |
---|---|
bitwise | 禁用位运算符 |
curly | 循环和条件语句必须使用大括号块包围 |
eqeqeq | 强制使用全等(===)和不全等(!==)来替代相等(==)和不相等(!=) |
freeze | 禁止重写原生对象原型 |
indent | 代码缩进宽度 |
noarg | 禁止使用arguments.callee和arguments.caller |
undef | 禁止使用未定义变量 |
unused | 禁止定义了变量却不使用 |
trailing | 禁止行尾空格 |
maxparams | 函数可接受的最大参数数量 |
maxlen | 每行代码最大字符串长度 |
松弛参数 | 作用 |
---|---|
boss | 允许在循环和条件语句中使用赋值( 如if(var i=0, len=...){ ) |
esnext | 允许ES6特性 |
loopfunc | 允许循环中定义函数 |
sub | 允许使用方括号语法获取对象属性 |
除此之外还有一个环境参数(Environments),这个参数告诉JSHint有一些全局变量已经被预定义。
环境参数 | 作用 |
---|---|
browser | 指定浏览器全局变量(document,navigator,FileReader等) |
devel | 指定用于调试的全局变量(console,alert等) |
jquery | 指定jquery |
module | 指定module |
... | 指定... |
具体完成配置查询 http://jshint.com/docs/options/
其他
JSCS
JSCS是一个代码风格检查器,它只匹配代码格式的问题,不匹配潜在的bug、error等。它拥有90多个不同的规则,但是如果不做配置的话就没有任何作用。换言之,一切JSCS的要做的东西都需要根据需求自定义开启。
优点:可以自定义插件进行扩展 缺点:慢
ESLint
ESLint是Zakas大神2013年开发的工具,它的特点是可扩展、每条规则独立、不内置编码风格。它默认包含了所有 JSLint、JSHint 中存在的规则,迁移容易,而且可以给规则设置“警告”、“错误”或者直接禁用几个等级。另外它也包含代码风格检测规则,并支持插件扩展。
优点:支持React JSX,支持ES6,支持插件扩展 缺点:慢
动态检查
静态地谈性能不能解决全部的问题,甚至说,大部分性能优化问题是需要程序真正跑起来才能去发现解决优化的。那么关于动态的检测、优化记录几个方法及工具。
我爱火狐
console对象最初是由mozilla提出的,虽然现在各个现代浏览器都实现了这个对象,并且99%也都满足了日常需求,不过在某些非常细微的地方还是略有差异。
console并不只是可以log、error、info等。
函数执行监控
这是一对函数,监控开始 console.profile(tag) 和 监控结束 console.profileEnd()。在这两个指令中间执行的所有逻辑调用会被记录并统计,并且被console.profileEnd返回。
比如现在有几个蛋疼的函数:
代码语言:javascript复制function iAmAFuckingFunction(){
for(var i=0; i<10 ;i ){
eggacheA(999);
}
eggacheB(9999);
}
function eggacheA(count){
for(var i=0; i<count; i ){
}
}
function eggacheB(count){
for(var i=0; i<count; i ){
}
}
可以在代码中这样加入调试
代码语言:javascript复制console.profile("蛋疼函数检测1");
iAmAFuckingFunction();
console.profileEnd();
然后可以在控制台中看到
在这个统计中可以看到从profile到profileEnd之间执行的逻辑有哪些函数被调用,被调用次数,执行时间,总时间等等各项信息。
另外在firebug控制台也有按钮可以直接使用profile
点击“概况”按钮,然后触发一些事件(交互逻辑、ajax等等),操作完毕再次点击“概况”按钮,就可以得到刚才操作所执行逻辑的信息。
比如,现在我想看看平台lazyload逻辑的相关执行信息,那么我先打开页面,点击“概况”
然后把页面向下滚动,滚动结束后再次点击“概况”
可以看到消耗时间最长的是jq的css函数,但这个是总时间,现在想看单个函数执行时间最长,那么点击“平均时间”tab
这个时候能看到最慢的函数执行时间了。前几个都是库,我需要看自己逻辑中的执行情况,那么在右边“文件”tab可以看到相关信息了。
执行时间监控
另外还有一对函数: console.time(tag) 与 console.timeEnd(tag)。它们的用法跟profile差不多,只不过返回的是两个指令之间的时间差。
还是刚才那三个蛋疼函数
代码语言:javascript复制console.time("eggache");
iAmAFuckingFunction();
console.timeEnd("eggache");
返回
另外console.timeEnd是有返回值的,返回值就是时间差的毫秒数。也就是说:
代码语言:javascript复制console.time("eggache");
iAmAFuckingFunction();
var timeSub = console.timeEnd("eggache");
//timeSub 0.698906173342948
声明:以上方法只能在firefox->firebug中使用,其他浏览器正确无法获取信息
YSlow
这是一个web性能工具,最早由Yahoo!基于firebug开发,现在已经扩展到各个浏览器都能够安装。它按照雅虎页面优化准则(基于34条那个版本比14条更细)来对网站进行性能分析,并对各个检测项按照A、B、C、D、E、F给出评级,当然也会有一个0~100的评分。
现在对腾讯教育平台首页进行YSlow Run Test
会看到一个执行进度条,片刻后执行完毕可以看到
平台首页得分是90分,评价还是很高的,而且这里有个小小的错误,YSlow不认识78910.url.cn,把这几个域名下的资源误认为是不在CDN之下,实际上这些是做了CDN的。所以其实评分还应该更高一点~~~~ 咳咳偏题了,继续说YSlow。
前面说了YSlow是基于雅虎页面优化准则来进行性能检测的,那么其实这其中大部分的事情也都在码农群体中心照不宣地遵守了,只是有一些东西也许随着技术的更新迭代不是那么完美适用了。比如“添加Expires头”这一条。这个准则的初衷其实是为了缓存文件来着,随着HTTP1.1的普及,在有Cache-Control头的情况下,其实没有Expires也是完全可以的。
附两张YSlow分析的图
最后
Timeline的图贴一张,不赘述了。