初探 performance – 监控网页与程序性能
您目前处于:开发&语言  -  HTML5  2016年05月04日  阅读 2040
“If you cannot measure it, you cannot improve it” ———— William Thomson

如果 Google 延迟 400ms,则搜索量下降 0.59%;Bing 延迟 2s,收入下降 4.3%;Yahoo 延迟 400ms,流量下降 5-9%;Mozilla 页面打开减少 2.2s,下载量提升 15.4%;Netflix 开启 Gzip,性能提升 13.25% 带宽减少50%。

性能影响了用户体验

加载的延迟、操作的卡顿等都会影响用户的使用体验。尤其是移动端,用户对页面响应延迟和连接中断的容忍度很低。想象一下你拿着手机打开一个网页想看到某个信息却加载半天的心情,你很可能选择直接离开换一个网页。谷歌也将页面加载速度作为 SEO 的一个权重。

性能会伴随产品的迭代而有所衰减

特别在移动端,网络一直是一个很大的瓶颈,而页面却越来越大,功能越来越复杂。并没有简单的几条黄金规则就可以搞定性能优化工作,我们需要一套性能监控系统持续监控、评估、预警页面性能状况、发现瓶颈,指导优化工作的进行。

监控用户的痛点

线上监控哪些指标呢?如何更好地反映用户感知?

根据用户的痛点,将浏览器加载过程抽取出四个关键指标,即白屏时间、首屏时间、用户可操作、总下载时间。

1. 确定统计起点

在用户输入 URL 或者点击链接的时候就开始统计,因为这样才能衡量用户的等待时间。如果你的用户高端浏览器占比很高,那么可以直接使用Navigation Timing接口来获取统计起点以及加载过程中的各个阶段耗时。

2. 统计白屏时间

用户从打开页面开始到页面开始有东西呈现为止,这过程中占用的时间就是白屏时间,也叫做首次渲染时间,chrome 高版本有 firstPaintTime 接口来获取这个耗时。

白屏时间出现在头部外链资源加载完附近,因为浏览器只有加载并解析完头部资源才会真正渲染页面。

3. 统计首屏时间

用户浏览器首屏内所有内容都呈现出来所花费的时间就是首屏时间。

4. 统计用户可操作和总下载

用户可操作默认可以统计domready时间,因为通常会在这时候绑定事件操作。总下载时间默认可以统计onload时间,这样可以统计同步加载的资源全部加载完的耗时。

网络耗时统计

网络耗时数据可以借助 Navigation Timing 接口获取,通过此接口可以轻松获取 DNS、TCP、首字节、html 传输等耗时,Navigation Timing 的接口示意图如下所示:

在 Chrome 浏览器控制台中执行 window.performance

让数据会说话

// 获取 performance 数据
var performance = {  
    // memory 是非标准属性,只在 Chrome 有
    memory: {
        usedJSHeapSize:  16100000, // JS 对象占用的内存,一定小于 totalJSHeapSize
        totalJSHeapSize: 35100000, // 可使用的内存
        jsHeapSizeLimit: 793000000 // 内存大小限制
    }, 
    navigation: {
        redirectCount: 0, // 如果有重定向的话,页面通过几次重定向跳转而来
        type: 0
    // 0   即 TYPE_NAVIGATENEXT 正常进入的页面(非刷新、非重定向等)
    // 1   即 TYPE_RELOAD 通过 window.location.reload() 刷新的页面
    // 2   即 TYPE_BACK_FORWARD 通过浏览器的前进后退按钮进入的页面(历史记录)
    // 255 即 TYPE_UNDEFINED 非以上方式进入的页面
    },
 
    timing: {
        // 在同一个浏览器上下文中,前一个网页 unload 的时间戳
        navigationStart: 1441112691935,
 
        // 前一个网页 unload 的时间戳
        unloadEventStart: 0,
 
        // 和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳
        unloadEventEnd: 0,
 
        // 第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0 
        redirectStart: 0,
 
        // 最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内部的重定向才算,否则值为 0 
        redirectEnd: 0,
 
        // 浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前
        fetchStart: 1441112692155,
 
        // DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
        domainLookupStart: 1441112692155,
 
        // DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
        domainLookupEnd: 1441112692155,
 
        // HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等
        // 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
        connectStart: 1441112692155,
 
        // HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等
        // 注意如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
        // 注意这里握手结束,包括安全连接建立完成、SOCKS 授权通过
        connectEnd: 1441112692155,
 
        // HTTPS 连接开始的时间,如果不是安全连接,则值为 0
        secureConnectionStart: 0,
 
        // HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存
        // 连接错误重连时,这里显示的也是新建立连接的时间
        requestStart: 1441112692158,
 
        // HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
        responseStart: 1441112692686,
 
        // HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存
        responseEnd: 1441112692687,
 
        // 开始解析渲染 DOM 树的时间
        // 此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
        domLoading: 1441112692690,
 
        // 完成解析 DOM 树的时间
        // Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
        // 注意只是 DOM 树解析完成,这时候并没有开始加载网页内的资源
        domInteractive: 1441112693093,
 
        // DOM 解析完成后,网页内资源加载开始的时间
        // 在 DOMContentLoaded 事件抛出前发生
        domContentLoadedEventStart: 1441112693093,
 
        // DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕)
        domContentLoadedEventEnd: 1441112693101,
 
        // DOM 树解析完成,且资源也准备就绪的时间
        // Document.readyState 变为 complete,并将抛出 readystatechange 相关事件
        domComplete: 1441112693214,
 
        // load 事件发送给文档,也即 load 回调函数开始执行的时间
        // 注意如果没有绑定 load 事件,值为 0
        loadEventStart: 1441112693214,
 
        // load 事件的回调函数执行完毕的时间
        loadEventEnd: 1441112693215
    }
};

使用 performance.timing 信息简单计算出网页性能数据

// 计算加载时间
function getPerformanceTiming () {  
    var performance = window.performance;
 
    if (!performance) {
        console.log('你的浏览器不支持 performance 接口');
        return;
    }
 
    var t = performance.timing;
    var times = {};
 
    //【重要】页面加载完成的时间
    times.loadPage = t.loadEventEnd - t.navigationStart;
 
    //【重要】解析 DOM 树结构的时间
    times.domReady = t.domComplete - t.responseEnd;
 
    //【重要】重定向的时间
    times.redirect = t.redirectEnd - t.redirectStart;
 
    //【重要】DNS 查询时间
    times.lookupDomain = t.domainLookupEnd - t.domainLookupStart;
 
    //【重要】读取页面第一个字节的时间    
    times.ttfb = t.responseStart - t.navigationStart;
 
    //【重要】内容加载完成的时间
    times.request = t.responseEnd - t.requestStart;
 
    //【重要】执行 onload 回调函数的时间
    times.loadEvent = t.loadEventEnd - t.loadEventStart;
 
    // DNS 缓存时间
    times.appcache = t.domainLookupStart - t.fetchStart;
 
    // 卸载页面的时间
    times.unloadEvent = t.unloadEventEnd - t.unloadEventStart;
 
    // TCP 建立连接完成握手的时间
    times.connect = t.connectEnd - t.connectStart;
 
    return times;
}

Reference:http://www.alloyteam.com/2015/09/explore-performance/


转载请并标注: “本文转载自 linkedkeeper.com ”

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

赞赏支持
分享到: 更多
作者  乔淑夷  发布于 2017年12月30日  阅读 70
作者 何昆 发布于 2017年08月14日  阅读 2007
如果你是一个WEB开发人员,你肯定遇到过跨域的问题。什么是跨域?我先假装你们不知道(^..^嘻嘻),域名你们都知道,比如www.baidu.com,www.jd.com等都属于域名,如果我想在京东的页面中通过一个关键字来请求百度获取搜索结果,这就是一个跨域请求。举个例子:民间一位姓陈的人家有一手上好的酿酒本事。他们家立下规矩,这门手艺只传自家孩子。那如果我这个姓何的想去学肯定会被扫地出门,除非得到...
作者  乔淑夷  发布于 2017年07月31日  阅读 1474
开发过程中我们遇到的一些JS的问题,总结一下,未完待续 ……1. 滚动条滚动到页面容器底部,设置滚动条距离顶部的高度为容器内容高度和容器可视区域高度的差,并添加动画。var obj = document.getElementById('msgList'); if(obj.scrollHeight > obj.clientHeight){ $(obj).animate({ ...
作者  乔淑夷  发布于 2017年07月27日  阅读 1207
组件(Component)是Vue.js的核心部分,组件的作用域是孤立的,所以不能在子组件模板内直接引用父组件的数据,但是组件之间的通信是必不可少的。组件A在其模板中使用了组件B,A组件要向B组件传递数据,B组件要将其内部发生的事情告知A组件,那么A、B组件怎么进行通信呢?Vue.js父子组件的关系可以总结为props down,events up,父组件通过props向下传递数据给子组件,子组件...
作者  乔淑夷  发布于 2017年07月19日  阅读 562
Yeoman是Google团队开发的项目,通过内部三个工具yo,grunt,bower协同工作,可以让网络前端开发者快速打造一个漂亮的网络应用。yo:脚手架工具,用于构建一个新的项目框架,项目工程依赖目录和文件生成工具,项目生产环境和编译环境生产工具bower:web开发的包管理,类似npm,npm专注于nodejs模块,bower专注于css、js、图像等前端内容管理,bower的运行依赖于版本...