欢迎你们收看聊一聊系列,这一套系列文章,能够帮助前端工程师们了解前端的方方面面(不只仅是代码):javascript
https://segmentfault.com/blog/frontenddriverhtml
上一篇文章咱们讨论了,如何进行前端日志打点统计:前端
http://www.javashuo.com/article/p-xebcpebm-z.htmlhtml5
这一篇咱们来看看如何进行速度统计java
网站的速度影响了用户访问网站最初的体验。试想,若是一个用户,在等待了若干秒后,仍是停留在白屏的状态,那么他的选择将是离开这个网站。性能统计有助于帮咱们检测网站的用户体验。nginx
这里引用百度百科中的一句话 ---- 一般一个网站,若是首屏时间在2秒之内是比较优秀的,5秒之内是能够接受的,5秒以上就不可容忍了。用户会选择刷新页面或马上离开。segmentfault
这里,有些数据须要与你们分享一下(来自FEX的统计):浏览器
产品 | 性能 | 收益 |
---|---|---|
延迟 400ms | 搜索量降低 0.59% | |
Bing | 延迟 2s | 收入降低 4.3% |
Yahoo | 延迟 400ms | 流量降低 5-9% |
Mozilla | 页面打开减小 2.2s | 下载量提高 15.4% |
Netflix | 开启 Gzip性能提高 13.25% | 带宽减小50% |
能够看到,速度,对于一个网站来讲,重要性可见一斑。服务器
这个指标对于大多数网站来讲,很是重要。那么何为首屏时间呢?引用百度百科里的一句话,就是:网络
网站用户体验的一个重要指标。 指一个网站被浏览器如IE窗口上部800*600的区域被充满所需时间。
其实就是你的网页刚进入时,渲染完整个浏览器屏幕的时间。
关因而否包含首屏全部的图片下载完成。这个网上有些争议,有的同窗说不包含图片,只要DOM+样式 都渲染完了,就算完成了。
笔者认为,既然是首屏,那么首屏上全部的东西都加载完成,让用户感觉不到还有没完成的部分,就算完成了。
因此,综合一下,我们的首屏时间,包括首屏的DOM元素的渲染,展示在用户第一屏幕的全部图片都完成。
其实Chrome提供开发着检查网站整个渲染过程的小公举,哦不,是小工具(如图1.1.1所示)在F12开发者工具的Network面板里面:
图1.1.1
这个是屏幕捕获的工具,能够看到整个网页的渲染过程。咱们接着来深究一下上述哪一个时间点是首屏时间点。
咱们来一块儿看看百度首页的首屏状况,因为百度首页加载比较快,因此这里我们模拟一下3G网的延迟(如图1.1.2):
图1.1.2
咱们看到,虽然在240ms的时候,网页算是被渲染出来了,可是仍是有不少空白的地方。
279MS的时候,虽然框架都被渲染完成了,DOM与样式也都渲染完成了,可是咱们看到图片还不完整,因此,固然也不算首屏完成了。
有的同窗会说,318ms的时候,总算完成了吧,nonono,咱们向后观察,就会发现还有一些元素会再被渲染出来。也就是说知道稳定以前,咱们都不能算首屏完成了。
知道487 ms的时候,页面才算加载完成了。而且以后不会再发生页面的抖动了。
看完这些,相信聪明的你内心已经有数了,什么是首屏时间。
这个其实很少说,读者也明白,就是页面处于空白的时间。页面空白,用户就会焦躁,而且变得不耐心。影响白屏时间的多数是:DNS解析耗时+服务端耗时+网络传输耗时。
顾名思义,这项指标值得是,咱们的网页用户可使用的时间。通常来说 domready时间,即是咱们的用户可操做时间了。
一般指,页面整体的下载时间,全部的页面资源都下载完成。
因为业务不一样,站长们所关心的时间必然也不一样了。好比你多是一个电商网站的站长,你关心你的第一屏商品到底展现的有多快( 一般这会带来更多的收入),因此,你须要监控你的商品展示的时间。
若是并不想要花费精力在这些统计上,只是要小小的关注一下的话,固然能够本身打开控制台,在页面的各个阶段,将时间打印出来,亦或者是使用html5新增的接口:performance来评估一下本身的网站到底差在哪里(如图2.0.1)。
图2.0.1
可是,你的测试并不能表明全部的用户的状况。并且,你须要一个监控程序,去时刻提醒着你,如今你的网站的速度处于什么情况。
因此,对于有追求一些的站长而言,笔者在这里更建议采用用户日志,即,在本身网站的代码中,增长统计,并把统计结果发送到服务器。在服务器采集这些日志,并产生一个监控的网站。其实大可没必要使用一些付费的服务,咱们本身就能够轻轻松松的作一个简答的速度监控服务。
在本文的第三节,咱们将会一块儿作一个小的速度监控服务的例子。不少站长甚至能够拿过来直接使用。接下来,咱们仍是针对以前咱们提到过的几个指标,注意讲解统计方法:
其实,对于网页高度小于屏幕的网站来讲,统计首屏时间很是的简单,只要在页面底部加上脚本打印当前时间便可,或者对于网页高度大于一屏的网页来讲,只要在估算接近于一屏幕的元素的位置后,打印一下当前时间便可。
好比,如今你有一个简单的网页(如图2.1.1所示):
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> </head> <body> <div>这是第一屏,这是第一屏</div> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <div>第一屏结尾,第一屏结尾</div> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> </body> </html>
图2.1.1
咱们须要统计首屏时间的话,则须要定义一个基准,就是--何时用户点开的当前网页,HTML5的performance接口提供了这个时间:performance.timing.navigationStart,这个就是用户访问咱们网页最开始的跳转时间了。
<head> <script type="text/javascript"> window.logInfo = {}; window.logInfo.openTime = performance.timing.navigationStart; </script> </head>
咱们在页面开头处,将基准记下。
接下来,在大约的首屏处加上咱们的统计:
<div>第一屏结尾,第一屏结尾</div> <script type="text/javascript"> window.logInfo.firstScreen = +new Date() - window.logInfo.openTime; console.log('首屏时间:', window.logInfo.firstScreen + 'ms'); </script>
咱们再来看看咱们的页面(如图2.1.2所示):
图2.1.2
便有了首屏时间。
霸特,霸特。同窗们不要激动的太早。咱们这个首屏时间,并不没有算上图片。因此,咱们得把首屏中全部图片的加载时间也算上。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> <script type="text/javascript"> window.logInfo = {}; window.logInfo.openTime = performance.timing.navigationStart; </script> </head> <body> <div>这是第一屏,这是第一屏</div> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <div>第一屏结尾,第一屏结尾</div> <script type="text/javascript"> (function logFirstScreen() { var images = document.getElementsByTagName('img'); var iLen = images.length; var curMax = 0; var inScreenLen = 0; // 图片的加载回调 function imageBack() { this.removeEventListener && this.removeEventListener('load', imageBack, !1); if (++curMax === inScreenLen) { // 若是全部在首屏的图片均已加载完成了的话,发送日志 log(); } } // 对于全部的位于指定区域的图片,绑定回调事件 for (var s = 0; s < iLen; s++) { var img = images[s]; var offset = { top: 0 }; var curImg = img; while (curImg.offsetParent) { offset.top += curImg.offsetTop; curImg = curImg.offsetParent; } // 判断图片在不在首屏 if (document.documentElement.clientHeight < offset.top) { continue; } // 图片尚未加载完成的话 if (!img.complete) { inScreenLen++; img.addEventListener('load', imageBack, !1); } } // 若是首屏没有图片的话,直接发送日志 if (inScreenLen === 0) { log(); } // 发送日志进行统计 function log () { window.logInfo.firstScreen = +new Date() - window.logInfo.openTime; console.log('首屏时间:', window.logInfo.firstScreen + 'ms'); } })(); </script> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> </body> </html>
以上封装的首屏时间函数,无依赖比较小巧,同窗们能够直接使用于本身的项目中。这样,咱们就轻轻松松的统计到了首屏时间。
能够在页面的head底部添加的JS代码来统计白屏时间,虽然这样作可能并不十分精准,可是也能够基本表明了首屏时间,如图2.2.1所示。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> <script type="text/javascript"> window.logInfo = {}; window.logInfo.openTime = performance.timing.navigationStart; window.logInfo.whiteScreenTime = +new Date() - window.logInfo.openTime; console.log('白屏时间:', window.logInfo.whiteScreenTime + 'ms'); </script> </head>
图2.2.1
前面提到过document.ready其实就能够算做咱们的用户可操做时间啦。咱们不妨直接试试,如图2.3.1所示:
document .addEventListener( 'DOMContentLoaded', function (event) { window.logInfo.readyTime = +new Date() - window.logInfo.openTime; console.log('用户可操做时间:', window.logInfo.readyTime); } );
图2.3.1
页面整体下载时间,使用window.onload
便可,这能够帮助咱们看看咱们全部的资源是否拖慢网页,如图2.4.1所示:
window.onload = function () { window.logInfo.allloadTime = +new Date() - window.logInfo.openTime; console.log('总下载时间:', window.logInfo.allloadTime + 'ms'); };
图2.4.1
咱们将上述的统计合并,一个完整的统计就出来了,如图2.5.1所示:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,minimum-scale=1.0,maximum-scale=1.0"> <script type="text/javascript"> window.logInfo = {}; window.logInfo.openTime = performance.timing.navigationStart; window.logInfo.whiteScreenTime = +new Date() - window.logInfo.openTime; </script> </head> <body> <div>这是第一屏,这是第一屏</div> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <div>第一屏结尾,第一屏结尾</div> <script type="text/javascript"> (function logFirstScreen() { var images = document.getElementsByTagName('img'); var iLen = images.length; var curMax = 0; var inScreenLen = 0; // 图片的加载回调 function imageBack() { this.removeEventListener && this.removeEventListener('load', imageBack, !1); if (++curMax === inScreenLen) { // 若是全部在首屏的图片均已加载完成了的话,发送日志 log(); } } // 对于全部的位于指定区域的图片,绑定回调事件 for (var s = 0; s < iLen; s++) { var img = images[s]; var offset = { top: 0 }; var curImg = img; while (curImg.offsetParent) { offset.top += curImg.offsetTop; curImg = curImg.offsetParent; } // 判断图片在不在首屏 if (document.documentElement.clientHeight < offset.top) { continue; } // 图片尚未加载完成的话 if (!img.complete) { inScreenLen++; img.addEventListener('load', imageBack, !1); } } // 若是首屏没有图片的话,直接发送日志 if (inScreenLen === 0) { log(); } // 发送日志进行统计 function log () { window.logInfo.firstScreen = +new Date() - window.logInfo.openTime; } })(); document .addEventListener( 'DOMContentLoaded', function (event) { window.logInfo.readyTime = +new Date() - window.logInfo.openTime; } ); window.onload = function () { window.logInfo.allloadTime = +new Date() - window.logInfo.openTime; var timname = { whiteScreenTime: '白屏时间', firstScreen: '首屏时间', readyTime: '用户可操做时间', allloadTime: '总下载时间' }; for (var i in timname) { console.log(timname[i] + ':' + window.logInfo[i] + 'ms'); } }; </script> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> <img src="http://static.oschina.net/uploads/space/2016/0623/152644_6UUC_1177792.png"> </body> </html>
图2.5.1
按照上一节( http://www.javashuo.com/article/p-xebcpebm-z.html )所说,咱们将这个日志发送到服务端去。
var logStr = ''; for (var i in timname) { logStr += '&' + i + '=' + window.logInfo[i]; } (new Image()).src = 'http://localhost:8091/?action=speedlog' + logStr;
开启咱们的nginx监听,并在服务端接收这条日志如图2.5.2,图2.5.3所示:
图2.5.2
图2.5.3
咱们看看日志里面是否是已经多了一条了呢?
要是再加以定时任务,日志采集等功能的辅助,咱们就能实时掌握本身网站的性能啦。
http://www.javashuo.com/article/p-wrkmdljz-gd.html
后续,咱们也会一块儿来聊聊,如何优化咱们的这些速度,以提升咱们的网站性能。
原创文章,版权全部,转载请注明出处