前端页面质量优化,前端品质与那多少个申报

By admin in 4858美高梅 on 2019年2月27日

前端质量优化 —— 前端品质分析

2018/01/11 · 基本功技术 ·
移动端

初稿出处: ouven   

前端质量优化是一个很宽泛的概念,本书前边的部分也多多少少涉及一些前端优化措施,那也是我们一贯在关切的一件重庆大学事务。协作各个艺术、手段、支持系统,前端优化的尾声目标都是升迁用户体验,改进页面品质,大家日常拼命实行前端页面优化,但却不经意了如此做的功力和含义。先不急于求成切磋前端优化具体能够怎么去做,先看看哪些是前者品质,应该怎样去探听和评论前端页面的属性。

普通前端品质能够认为是用户获得所须求页面数据或举行有些页面动作的1个实时性指标,一般以用户期望获取数据的操作到用户实际取得多少的时间间隔来度量。例如用户愿意获取数据的操作是开辟有些页面,那么这几个操作的前端品质就足以用该用户操作起来到显示屏体现页面内容给用户的那段时光间隔来评判。用户的等候延时能够分成两部分:可控等待延时和不可控等待延时。可控等待延时能够通晓为能透过技术手段和优化来创新减少的局地,例如减小图片大小让请求加载更快、减弱HTTP请求数等。不可控等待延时则是无法或很难通过上下端技术手段来创新优化的,例如鼠标点击延时、CPU总计时间延时、ISP(Internet
ServiceProvider,互连网服务提供商)网络传输延时等。所以要理解的是,前端中的全数优化都是指向可控等待延时这有的来进行的,上面来询问一下什么赢得和评价三个页面包车型的士求实性质。

5.4.1 前端品质测试

获得和度量一个页面包车型地铁性格,重要能够因此以下多少个地点:Performance Timing
API、Profile工具、页面埋点计时、财富加载时序图分析。

前者品质与丰富申报

2018/08/22 · 基本功技术 ·
性能

原稿出处: counterxing   

1.关键点

  分页面、区域、浏览器、品质指标

  页面包车型地铁品质指标详解:

  白屏时间(first Paint
提姆e)——用户从打开页面起始到页面开头有东西展现截至

  首屏时间——用户浏览器首屏内全数剧情都表现出来所费用的日子

  用户可操作时间(dom
Interactive)——用户能够拓展正规的点击、输入等操作,私下认可能够计算domready时间,因为平日会在那时候绑定事件操作

  总下载时间——页面全部财富都加载成功并显现出来所花的时光,即页面
onload 的年华

 

  规定计算源点:

  咱们须求在用户输入 URL
大概点击链接的时候就起来总计,因为如此才能衡量用户的等候时间。高端浏览器Navigation
Timing接口;普通浏览器通过 cookie 记录时间戳的法门来总计,须求小心的是
Cookie 格局只好计算到站内跳转的数额。

  

① 、互联网加载类

一、Performance Timing API

Performance Timing API是1个支持Internet Explorer
9以上版本及WebKit内核浏览器中用来记录页面加载和分析进度中珍视时间点的建制,它可以详细记录每一种页面能源从开始加载到剖析实现这一历程中具体操作产生的时间点,那样依据初叶和终止时间戳就足以测算出这么些进度所花的日子了。

图1为W3C标准中Performance
Timing财富加载和分析进程记录各种关键点的示意图,浏览器中加载和剖析三个HTML文件的详尽进程先后经历unload、redirect、App
Cache、DNS、TCP、Request、Response、Processing、onload多少个阶段,各样进度开首和完工的紧要时刻戳浏览器已经采纳performance.timing来记录了,所以基于这几个记录并组成简单的乘除,大家就可以取得页面中各类进度所费用的光阴。

4858美高梅 1

图1 performance API关键时刻点记录

function performanceTest() { let timing = performance.timing, readyStart
= timing.fetchStart – timing.navigationStart, redirectTime =
timing.redirectEnd – timing.redirectStart, appcacheTime =
timing.domainLookupStart – timing.fetchStart, unload伊芙ntTime =
timing.unload伊夫ntEnd – timing.unload伊夫ntStart, lookupDomainTime =
timing.domainLookupEnd – timing.domainLookupStart, connectTime =
timing.connectEnd – timing.connectStart, requestTime =
timing.responseEnd – timing.requestStart, initDomTreeTime =
timing.domInteractive – timing.responseEnd, domReadyTime =
timing.domComplete – timing.domInteractive, load伊芙ntTime =
timing.load伊芙ntEnd – timing.load伊夫ntStart, loadTime =
timing.load伊夫ntEnd – timing.navigationStart;
console.log(‘准备新页面时间耗费时间: ‘ + readyStart); console.log(‘redirect
重定向耗费时间: ‘ + redirectTime); console.log(‘Appcache 耗费时间: ‘ +
appcacheTime); console.log(‘unload 前文书档案耗费时间: ‘ + unload伊夫ntTime);
console.log(‘DNS 查询耗费时间: ‘ + lookupDomainTime);
console.log(‘TCP连接耗费时间: ‘ + connectTime);
console.log(‘request请求耗费时间: ‘ + requestTime);
console.log(‘请求完毕至DOM加载: ‘ + initDomTreeTime);
console.log(‘解析DOM树耗费时间: ‘ + domReadyTime);
console.log(‘load事件耗费时间: ‘ + load伊夫ntTime);
console.log(‘加载时间耗时: ‘ + loadTime); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function performanceTest() {
    let timing = performance.timing,
    readyStart = timing.fetchStart – timing.navigationStart,
    redirectTime = timing.redirectEnd – timing.redirectStart,
    appcacheTime = timing.domainLookupStart – timing.fetchStart,
    unloadEventTime = timing.unloadEventEnd – timing.unloadEventStart,
    lookupDomainTime = timing.domainLookupEnd – timing.domainLookupStart,
    connectTime = timing.connectEnd – timing.connectStart,
    requestTime = timing.responseEnd – timing.requestStart,
    initDomTreeTime = timing.domInteractive – timing.responseEnd,
    domReadyTime = timing.domComplete – timing.domInteractive,
    loadEventTime = timing.loadEventEnd – timing.loadEventStart,
    loadTime = timing.loadEventEnd – timing.navigationStart;
    console.log(‘准备新页面时间耗时: ‘ + readyStart);
    console.log(‘redirect 重定向耗时: ‘ + redirectTime);
    console.log(‘Appcache 耗时: ‘ + appcacheTime);
    console.log(‘unload 前文档耗时: ‘ + unloadEventTime);
    console.log(‘DNS 查询耗时: ‘ + lookupDomainTime);
    console.log(‘TCP连接耗时: ‘ + connectTime);
    console.log(‘request请求耗时: ‘ + requestTime);
    console.log(‘请求完毕至DOM加载: ‘ + initDomTreeTime);
    console.log(‘解析DOM树耗时: ‘ + domReadyTime);
    console.log(‘load事件耗时: ‘ + loadEventTime);
    console.log(‘加载时间耗时: ‘ + loadTime);
}

经过地方的日子戳总括可以得到多少个关键步骤所开支的光阴,对前者有含义的多少个经过首假若分析DOM树耗费时间、load事件耗费时间和总体加载进度耗时等,然则在页面品质获得时大家能够尽恐怕取得更详实的数目消息,以供前面分析。除了能源加载解析的根本点计时,performance还提供了一些其他方面的效果,大家得以依照具体要求进行抉择使用。

performance.memory // 内部存款和储蓄器占用的现实性数量 performance.now() //
performance.now()方法再次来到当前网页自performance.timing到前天的时刻,可以精确到微秒,用于特别纯粹的计数。但骨子里,近日网页质量通过飞秒来计量就足足了。
performance.getEntries() // 获取页面全数加载财富的performance
timing意况。浏览器获取网页时,会对网页中每贰个对象(脚本文件、样式表、图片文件等)发出3个HTTP请求。performance.getEntries方法以数组格局重返全部请求的年月总括新闻。
performance.navigation //
performance还足以提供用户作为音讯,例如互连网请求的档次和重定向次数等,一般都存放在performance.navigation对象里面。
performance.navigation.redirectCount // 记录当前网页重定向跳转的次数。

1
2
3
4
5
performance.memory // 内存占用的具体数据
performance.now() // performance.now()方法返回当前网页自performance.timing到现在的时间,可以精确到微秒,用于更加精确的计数。但实际上,目前网页性能通过毫秒来计算就足够了。
performance.getEntries() // 获取页面所有加载资源的performance timing情况。浏览器获取网页时,会对网页中每一个对象(脚本文件、样式表、图片文件等)发出一个HTTP请求。performance.getEntries方法以数组形式返回所有请求的时间统计信息。
performance.navigation // performance还可以提供用户行为信息,例如网络请求的类型和重定向次数等,一般都存放在performance.navigation对象里面。
performance.navigation.redirectCount // 记录当前网页重定向跳转的次数。

参考资料:https://www.w3.org/TR/resource-timing/。

概述

对于后台开发来说,记录日志是一种拾分常见的成本习惯,常常大家会利用try...catch代码块来积极抓获错误、对于每一遍接口调用,也会记录下每回接口调用的日子消耗,以便我们监察和控制服务器接口质量,举行难题排查。

刚进商店时,在进行Node.js的接口开发时,笔者不太习惯每一次排查难点都要经过跳板机登上服务器看日志,后来逐步习惯了那种办法。

举个例证:

JavaScript

/** * 获取列表数据 * @parma req, res */ exports.getList = async
function (req, res) { //获取请求参数 const openId =
req.session.userinfo.openId; logger.info(`handler getList, user openId
is ${openId}`); try { // 获得列表数据 const startTime = new
Date().get提姆e(); let res = await ListService.getListFromDB(openId);
logger.info(`handler getList, ListService.getListFromDB cost time ${new
Date().getTime() – startDate}`); // 对数码处理,重临给前端 // … }
catch(error) { logger.error(`handler getList is error,
${JSON.stringify(error)}`); } };

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 获取列表数据
* @parma req, res
*/
exports.getList = async function (req, res) {
    //获取请求参数
    const openId = req.session.userinfo.openId;
    logger.info(`handler getList, user openId is ${openId}`);
 
    try {
        // 拿到列表数据
        const startTime = new Date().getTime();
        let res = await ListService.getListFromDB(openId);
        logger.info(`handler getList, ListService.getListFromDB cost time ${new Date().getTime() – startDate}`);
        // 对数据处理,返回给前端
        // …
    } catch(error) {
        logger.error(`handler getList is error, ${JSON.stringify(error)}`);
    }
};

以下代码常常会冒出在用Node.js的接口中,在接口中会总结查询DB所耗时间、亦恐怕总结RPC服务调用所耗费时间间,以便监测质量瓶颈,对品质做优化;又或然对充裕使用try ... catch积极抓获,以便随时对难点展开追思、还原难点的风貌,进行bug的修复。

而对于前端来说吧?能够看之下的景观。

最近在展开贰个急需开发时,偶尔发现webgl渲染印象退步的场馆,或然说印象会并发解析战败的动静,我们兴许根本不知晓哪张印象会解析或渲染战败;又或如最近支付的别的3个急需,大家会做3个有关webgl渲染时间的优化和印象预加载的急需,要是缺乏品质监察和控制,该如何总结所做的渲染优化和印象预加载优化的优化比例,怎么着注解本人所做的工作具有价值呢?大概是透过测试同学的黑盒测试,对优化前后的光阴开展录屏,分析从进来页面到影象渲染完结到底经过了有点帧图像。那样的多少,恐怕既不规范、又相比较片面,设想测试同学并不是真正的用户,也无力回天苏醒真实的用户他们所处的互连网环境。回过头来发现,大家的品种,即便在服务端层面做好了日记和性子总括,但在前端对丰裕的监察和属性的总括。对于前端的属性与尤其申报的方向探索是有需求的。

2.什么总括质量指标的年月

前端页面质量优化,前端品质与那多少个申报。1.首屏数据请求提前,制止JavaScript文件加载后才请求数据
2.首屏加载和按需加载,非首屏内容滚屏加载,保障首屏内容最小化
相似推荐活动端页面首屏数据显示延时最长不超过3秒。近期中国移动3G的网络速度为338KB/s(2.71Mb/s),所以推举首屏全体财富大小不抢先1014KB,即大致不超过1MB。
3.模块化能源相互下载
在运动端能源加载中,尽量保障JavaScript能源互相加载,首要指的是模块化JavaScript财富的异步加载,例如英特尔的异步模块,使用并行的加载形式能够裁减两个文本财富的加载时间。
4.inline首屏少不了的CSS和JavaScript
一般而言为了在HTML加载成功时能使浏览器中有大旨的样式,需求将页面渲染时必需的CSS和JavaScript通过<script>或<style>内联到页面中,制止页面HTML载入完毕到页面内容展现那段进程中页面出现空白
5.meta dns prefetch设置DNS预解析
安装文件财富的DNS预解析,让浏览器提前解析获取静态财富的主机IP,幸免等到请求时才发起DNS解析请求。平时在运动端HTML中得以选用如下情势完毕。

二、 Profile工具

Performance 提姆ing
API描述了页面财富从加载到剖析各种阶段的进行关键点时间记下,不过力不从心计算JavaScript执行进程中系统能源的占有意况。Profile是Chrome和Firefox等规范浏览器提供的一种用于测试页面脚本运维时系统内存和CPU能源占用意况的API,以Chrome浏览器为例,结合Profile,能够完成以下多少个效率。

1.分析页面脚本执行进度中最耗财富的操作

2.笔录页面脚本执行进程中JavaScript对象消耗的内部存储器与堆栈的应用状态

3.检查和测试页面脚本执行进度中CPU占用景况

使用console.profile()和console.profileEnd()就可以分析中间一段代码执行时系统的内部存储器或CPU能源的损耗情况,然后合作浏览器的Profile查占星比消耗系统内部存款和储蓄器或CPU财富的操作,那样就能够有针对性地举办优化了。

console.profile(); // TODOS,要求测试的页面逻辑动作 for (let i = 0; i
< 一千00; i++) { console.log(i * i); } console.profileEnd();

1
2
3
4
5
6
console.profile();
// TODOS,需要测试的页面逻辑动作
for (let i = 0; i < 100000; i++) {
    console.log(i * i);
}
console.profileEnd();

足够捕获

对在此以前端来说,大家须求的非凡捕获无非为以下三种:

  • 接口调用情形;
  • 页面逻辑是还是不是错误,例如,用户进入页面后页面显示白屏;

对此接口调用情状,在前端常常须要申报客户端相关参数,例如:用户OS与浏览器版本、请求参数(如页面ID);而对于页面逻辑是还是不是错误问题,平时除了用户OS与浏览器版本外,供给的是报错的库房音讯及现实报错地点。

2.1白屏时间

  公式:

  白屏时间=开端渲染时间(首字节时光+HTML下载完结时间)+头部财富加载时间

  

  何以获得:

  chrome 高版本:

  window.chrome.load提姆es().firstPaintTime loadTimes获取的结果

4858美高梅 2

{
  connectionInfo: "http/1",
  finishDocumentLoadTime: 1422412260.278667,
  finishLoadTime: 1422412261.083637,
  firstPaintAfterLoadTime: 1422412261.094726,
  firstPaintTime: 1422412258.085214,
  navigationType: "Reload",
  npnNegotiatedProtocol: "unknown",
  requestTime: 0,
  startLoadTime: 1422412256.920803,
  wasAlternateProtocolAvailable: false,
  wasFetchedViaSpdy: false,
  wasNpnNegotiated: false
}

4858美高梅 3

   所以总计公式:

(chrome.loadTimes().firstPaintTime - chrome.loadTimes().startLoadTime)*1000

 

  其余浏览器:

  大部分浏览器没有一定函数,必须想别的事办公室法来监测。仔细考察 WebPagetest
视图分析发现,白屏时间出现在头顶外链资源加载完附近,因为浏览器唯有加载并分析完尾部能源才会真的渲染页面。基于此大家能够透过拿到底部财富加载完的每一天来仿佛计算白屏时间。固然并不规范,但却考虑了震慑白屏的机要要素:首字节时刻和尾部能源加载时间(HTML下载完结时间相当细小)。

  4858美高梅 4

  有三个点:mod_36ad799.js等多少个js为啥会在hm.js在此以前下载?html代码如下

  4858美高梅 5

  那相似与我们熟习的本子阻塞解析不符啊,理应是本子插入hm.js在先,导致DOM树改变,重新绘制DOM树,然后继续往下分析……原因是现行反革命的浏览器对这些历程做了优化:

<meta http-equiv=”x-dns-prefetch-control” content=”on”>
<link rel=”dns-prefetch” href=”//cdn.domain.com”>
6.财富预加载
对于移动端首屏加载后恐怕会被利用的财富,需求在首屏达成加载后连忙举办加载,保障在用户需求浏览时已经加载成功,那时候要是再去异步请求就展现一点也不快。
7.理所当然接纳MTU策略
经常状态下,大家觉得TCP互联网传输的最大传输单元(马克西姆um Transmission
Unit,MTU)为1500B,即互连网一个猎豹CS6TT(Round-Trip
Time,互连网请求往返时间)时间内能够传输的数据量最大为1500字节。由此,在前后端分离的费用形式中,尽量保障页面包车型客车HTML内容在1KB以内,那样全体HTML的剧情请求就可以在叁个CRUISERTT时间内央求完毕,最大限度地提升HTML载入速度。

③ 、 页面埋点计时

应用Profile能够在任其自然程度上救助大家分析页面包车型地铁性子,但缺点是不够利索。实际项目中,大家不会过多关切页面内部存款和储蓄器或CPU能源的成本情状,因为JavaScript有自动内部存款和储蓄器回收机制。大家关心越多的是页面脚本逻辑执行的岁月。除了Performance
Timing的关键过程耗费时间总括,大家还盼望检测代码的具体分析或施行时间,那就无法写过多的console.profile()和console.profileEnd()来逐段达成,为了尤其简明地拍卖那种场合,往往选择经过脚本埋点计时的法门来总结每部分代码的周转时刻。

页面JavaScript埋点计时相比较简单达成,和Performance
Timing记录时间戳有点类似,我们得以记录JavaScript代码开端推行的年华戳,前边在要求记录的地点埋点记录结束时的大运戳,最后通过差值来测算一段HTML解析或JavaScript解析执行的岁月。为了便于操作,能够将有个别操作起来和终结的时间戳记录到1个数组中,然后分析数组之间的距离就取得每种步骤的推行时间,上边来看3个时日点记录和分析的例证。

let timeList = []; function addTime(tag) { timeList.push({ “tag”: tag,
“time”: +new Date }); } addTime(“loading”); timeList.push({ “tag”:
“load”, “time”: +new Date() }); // TODOS,load加载时的操作
timeList.push({ “tag”: “load”, “time”: +new Date() }); timeList.push({
“tag”: “process”, “time”: +new Date() }); // TODOS,process处理时的操作
timeList.push({ “tag”: “process”, “time”: +new Date() });
parseTime(timeList); // 输出{load: 时间微秒数,process: 时间飞秒数}
function parseTime(time) { let timeStep = {}, end提姆e; for (let i = 0,
len = time.length; i < len; i++) { if (!time[i]) continue; endTime
= {}; for (let j = i + 1; j < len; j++) { if (time[j] &&
time[i].tag == time[j].tag) { endTime.tag = time[j].tag;
endTime.time = time[j].time; time[j] = null; } } if (endTime.time
>= 0 && endTime.tag) { timeStep[endTime.tag] = endTime.time –
time[i].time; } } return timeStep; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
let timeList = [];
function addTime(tag) {
    timeList.push({
        "tag": tag,
        "time": +new Date
    });
}
addTime("loading");
timeList.push({
    "tag": "load",
    "time": +new Date()
});
// TODOS,load加载时的操作
timeList.push({
    "tag": "load",
    "time": +new Date()
});
timeList.push({
    "tag": "process",
    "time": +new Date()
});
// TODOS,process处理时的操作
timeList.push({
    "tag": "process",
    "time": +new Date()
});
parseTime(timeList); // 输出{load: 时间毫秒数,process: 时间毫秒数}
function parseTime(time) {
    let timeStep = {},
    endTime;
    for (let i = 0, len = time.length; i < len; i++) {
        if (!time[i]) continue;
        endTime = {};
        for (let j = i + 1; j < len; j++) {
            if (time[j] && time[i].tag == time[j].tag) {
                endTime.tag = time[j].tag;
                endTime.time = time[j].time;
                time[j] = null;
            }
        }
        if (endTime.time >= 0 && endTime.tag) {
            timeStep[endTime.tag] = endTime.time – time[i].time;
        }
    }
    return timeStep;
}

那种措施平时在运动端页面中应用,因为运动端浏览器HTML解析和JavaScript执行相对较慢,日常为了拓展品质优化,我们需求找到页面中履行JavaScript耗费时间的操作,假若将第2JavaScript的执行进度进展埋点计时并反映,就能够轻松找出JavaScript执行慢的地点,并有指向地拓展优化。

13分捕获方法

处理脚本及样式表的一一(The order of processing scripts and style sheets)

二、缓存类

四 、能源加载时序图

笔者们还是能借助浏览器或任何工具的财富加载时序图来帮衬分析页面财富加载进程中的质量难点。那种办法能够粗粒度地宏观分析浏览器的富有能源文件请求耗费时间和文件加载顺序情状,如保障CSS和数据请求等重点财富优先加载,JavaScript文件和页面中国和南美洲重点图片等剧情延后加载。即便因为某些财富的加载拾壹分耗费时间而堵塞了页面包车型大巴始末体现,那就要注重考虑。所以,大家需求通过财富加载时序图来援助分析页面上能源加载顺序的标题。

4858美高梅 6

图2

图2为使用Fiddler获取浏览器访问地址
时的能源加载时序图。依据此图,我们可以很直观地看出页面上各种财富加载进度所急需的时辰和先后顺序,有利于找出加载进程中比较耗费时间的公文能源,扶助大家有针对地举行优化。

1 赞 2 收藏
评论

4858美高梅 7

大局捕获

能够经过全局监听格外来捕获,通过window.onerror或者addEventListener,看以下例子:

JavaScript

window.onerror = function(errorMessage, scriptU揽胜I, lineNo, columnNo,
error) { console.log(‘errorMessage: ‘ + errorMessage); // 相当信息console.log(‘scriptU陆风X8I: ‘ + scriptUPAJEROI); // 卓殊文件路径
console.log(‘lineNo: ‘ + lineNo); // 非凡行号 console.log(‘columnNo: ‘ +
columnNo); // 卓殊列号 console.log(‘error: ‘ + error); // 至极堆栈音信// … // 非凡上报 }; throw new Error(‘那是1个不当’);

1
2
3
4
5
6
7
8
9
10
window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
  console.log(‘errorMessage: ‘ + errorMessage); // 异常信息
  console.log(‘scriptURI: ‘ + scriptURI); // 异常文件路径
  console.log(‘lineNo: ‘ + lineNo); // 异常行号
  console.log(‘columnNo: ‘ + columnNo); // 异常列号
  console.log(‘error: ‘ + error); // 异常堆栈信息
  // …
  // 异常上报
};
throw new Error(‘这是一个错误’);

4858美高梅 8

通过window.onerror事件,能够取得具体的相当新闻、很是文件的UKugaL、卓殊的行号与列号及特其他库房消息,再捕获极度后,统一举报至大家的日记服务器。

亦或是,通过window.addEventListener措施来进行非凡申报,道理同理:

JavaScript

window.add伊夫ntListener(‘error’, function() { console.log(error); // …
// 至极上报 }); throw new Error(‘那是一个荒唐’);

1
2
3
4
5
6
window.addEventListener(‘error’, function() {
  console.log(error);
  // …
  // 异常上报
});
throw new Error(‘这是一个错误’);

4858美高梅 9

  脚本

  web的形式是3头的,开发者希望解析到一个script标签时立即解析执行脚本,并阻塞文书档案的剖析直到脚本执行完。借使脚本是外引的,则网络必须先请求到那些能源——那几个进度也是手拉手的,会阻塞文书档案的剖析直到能源被呼吁到。那么些形式保持了成都百货上千年,并且在html4及html5中都特地钦命了。开发者能够将脚本标识为defer,以使其不封堵文书档案解析,并在文档解析甘休后实施。Html二5日增了符号脚本为异步的选项,以使脚本的解析执行使用另三个线程。

1.理所当然选拔浏览器缓存
而外上面说到的应用Cache-Control、Expires、Etag和Last-Modified来设置HTTP缓存外,在活动端还是能利用localStorage等来保存AJAX再次来到的数目,大概应用localStorage保存CSS或JavaScript静态能源内容,完结移动端的离线应用,尽可能收缩互连网请求,保证静态能源内容的飞快加载。
2.静态资源离线方案
对此运动端或Hybrid应用,能够设置离线文件或离线包机制让静态能源请求从当地读取,加速资源载入速度,并促成离线更新。
3.品尝利用AMP HTML
AMP HTML能够看做优化前端页面质量的二个化解方案,使用AMP
Component中的成分来代替本来的页面成分实行直接渲染。
<amp-video width=”400″ height=”300″
src=”http://www.domain.com/videos/myvideo.mp4″
poster= “path/poster.jpg”>
<div fallback>

try… catch

使用try... catch固然能够较好地拓展相当捕获,不至于使得页面由于一处错误挂掉,但try ... catch破获情势展示过于臃肿,大多代码应用try ... catch包装,影响代码可读性。

  预解析(Speculative parsing)

  Webkit和Firefox都做了那么些优化,当执行脚本时,另三个线程解析剩下的文书档案,并加载后边需求通过网络加载的财富。那种办法得以使能源相互加载从而使全体进程更快。须要注意的是,预解析并不改动Dom树,它将以此工作留给主解析进程,自个儿只分析外部财富的引用,比如外表脚本、样式表及图片。

三、图片类

常见难点

  样式表(Style sheets)

  样式表选择另一种分裂的情势。理论上,既然样式表不转移Dom树,也就从未有过要求停下文书档案的解析等待它们,然则,存在2个题材,脚本或许在文书档案的分析进度中呼吁样式音信,如若体制还并未加载和分析,脚本将获得错误的值,显著那将会造成比比皆是题材,那看起来是个边缘情状,但确确实实很宽泛。Firefox在存在样式表还在加载和剖析时打断全部的台本,而Chrome只在当脚本打算访问一些大概被未加载的样式表所影响的一定的体制属性时才阻塞这几个本子。

  所以就取得了地点的至极结果

  看看IE的处理

  4858美高梅 10

   

  回归正题,普通浏览器需求获得三个时间:起始渲染时间底部能源加载时间:

  起初渲染时间:

  亟需借助浏览器的navigator
timing属性performance;window.performance.timing(Navigation
timing质量时间线) 相关属性:

4858美高梅 11

// 在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
navigationStart: 1441112691935,

// 前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
unloadEventStart: 0,
unloadEventEnd: 0,

// 第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0 
redirectStart: 0,
redirectEnd: 0,
 ...
 // 开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
domLoading: 1441112692690,
 ...

4858美高梅 12

  

var timing = performance.timing;

var loadingTime = timing .domLoading - timing.navigationStart;//开始渲染时间

   看一下navigator timing浏览器支持情状

  4858美高梅 13

  对于IE等低版本浏览器是那一个的。

  IE8 等低版本浏览器 通过 cookie 记录时间戳的措施来总括,供给留意的是
Cookie 格局只可以计算到站内跳转的数码。 第三回跻身没有好的计算格局。

   

  头顶资源加载时间: 

4858美高梅 14

<!DOCTYPE HTML>
<html>
    <head>
        <meta charset="UTF-8"/>
    <script>
      var start_time = +new Date; //测试时间起点,实际统计起点为 DNS 查询
    </script>
    <!-- 3s 后这个 js 才会返回 -->
    <script src="script.php"></script>  
    <script>
      var end_time = +new Date; //时间终点
      var headtime = end_time - start_time; //头部资源加载时间    
      console.log(headtime);
    </script>
    </head> 
    <body>     
    <p>在头部资源加载完之前页面将是白屏</p>
    <p>script.php 被模拟设置 3s 后返回,head 底部内嵌 JS 等待前面 js 返回后才执行</p>
    <p>script.php 替换成一个执行长时间循环的 js 效果也一样</p>  
    </body>
</html>

4858美高梅 15

   那几个相比较不难,在head的面前计时伊始,在head最末尾计时甘休,中间的差值就总结为底部能源加载时间。

  所以,最后计算方法:

var firstPaintTime = end_time - performance.timing.navigationStart

  

1.图纸压缩处理
2.应用较小的图样,合理运用base64内嵌图片
3.采纳更高压缩比格式的图形
利用全部较高压缩比格式的图片,如webp等。
4.图纸懒加载
5.应用Media Query或srcset依照区别荧屏加载不相同大小图片
在介绍响应式的章节中大家询问到,针对不一致的活动端荧屏尺寸和分辨率,输出不一致大小的图样或背景图能有限协理在用户体验不下落的前提下节省网络流量,加速局地机型的图纸加载速度,这在活动端卓殊值得推荐。
6.运用iconfont代替图片图标
7.概念图片大小限制
加载的单张图纸一般建议不当先30KB

跨域脚本不可能精确捕获非凡

一般性状态下,大家会把静态财富,如JavaScript本子放到专门的静态财富服务器,亦或许CDN,看之下例子:

<!DOCTYPE html> <html> <head>
<title></title> </head> <body> <script
type=”text/javascript”> // 在index.html window.onerror =
function(errorMessage, scriptU帕杰罗I, lineNo, columnNo, error) {
console.log(‘errorMessage: ‘ + errorMessage); // 至极音信console.log(‘scriptU安德拉I: ‘ + scriptU途观I); // 卓殊文件路径
console.log(‘lineNo: ‘ + lineNo); // 十分行号 console.log(‘columnNo: ‘ +
columnNo); // 非凡列号 console.log(‘error: ‘ + error); // 卓殊堆栈音信// … // 非常上报 }; </script> <script
src=”./error.js”></script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
  <title></title>
</head>
<body>
  <script type="text/javascript">
    // 在index.html
    window.onerror = function(errorMessage, scriptURI, lineNo, columnNo, error) {
      console.log(‘errorMessage: ‘ + errorMessage); // 异常信息
      console.log(‘scriptURI: ‘ + scriptURI); // 异常文件路径
      console.log(‘lineNo: ‘ + lineNo); // 异常行号
      console.log(‘columnNo: ‘ + columnNo); // 异常列号
      console.log(‘error: ‘ + error); // 异常堆栈信息
      // …
      // 异常上报
    };
 
  </script>
  <script src="./error.js"></script>
</body>
</html>

JavaScript

// error.js throw new Error(‘那是二个不当’);

1
2
// error.js
throw new Error(‘这是一个错误’);

4858美高梅 16

结果呈现,跨域之后window.onerror常有捕获不到科学的不胜音信,而是统一再次来到三个Script error

化解方案:对script标签扩大一个crossorigin=”anonymous”,并且服务器添加Access-Control-Allow-Origin

<script src=””
crossorigin=”anonymous”></script>

1
<script src="http://cdn.xxx.com/index.js" crossorigin="anonymous"></script>

 2.2首屏时间

  首屏时间的总括比较复杂,因为关乎图片等多样成分及异步渲染等格局。观察加载视图可发现,影响首屏的显要要素的图纸的加载。通过总计首屏内图片的加载时间便能够获取首屏渲染完毕的年华。总括流程如下:

  首屏位置调用 API 开始统计 -> 绑定首屏内所有图片的 load 事件 -> 页面加载完后判断图片是否在首屏内,找出加载最慢的一张 -> 首屏时间

  那是一起加载情形下的简单计算逻辑,别的索要留意的几点:

  • 页面存在 iframe 的情景下也亟需判定加载时间
  • gif 图片在 IE 上或许再度触发 load 事件需排除
  • 异步渲染的情状下应在异步获取数据插入之后再总结首屏
  • css 主要背景图片能够通过 JS 请求图片 url 来总结(浏览器不会重复加载)
  • 没有图片则以总计 JS 执行时间为首屏,即认为文字出现时间

4858美高梅 17

//IE gif重复onload解决
var img=new Image(); 
img.load=function(){ 
//do something 
img.load=null;//重新赋值为null 
} 
img.src='××.gif';

4858美高梅 18

   

  总结划办公室法1:

  原理:在首屏渲染此前埋上拍卖逻辑,使用定时器不断的去检查和测试img节点的图样。判断图片是不是在首屏和加载成功,找到首屏中加载时间最慢的的图纸完结的时刻,从而总计出首屏时间。要是首屏有没有图表,若是没图片就用domready时间。

  缺点: 1.浏览器定时器最大精度为55ms 2.背景图片加载没有计算在内
3.不断检查和测试并履行的台本耗费时间

4858美高梅 19 View Code

   

  总结方法2:

  原理:对于网页中度小于荧屏的网站以来,只要在页面头部加上脚本打字与印刷当前时间即可;恐怕对于网页中度当先一屏的网页来说,只要在打量接近于一显示屏的成分的职位后,打字与印刷一下脚下光阴。当然那些日子要得把首屏中拥有图片的加载时间也算上。

  缺点: 1.亟待种种页面手动参加到相应位置 2.背景图片加载没有测算在内

4858美高梅 20 View Code

  

四、脚本类
1.尽量运用id选取器
选料页面DOM成分时尽大概使用id采用器,因为id选择器速度最快。
2.靠边缓存DOM对象
对于需求重复使用的DOM对象,要优先设置缓存变量,幸免每回使用时都要从一切DOM树中重新寻找。
// 不推荐
$(‘#mod .active’).remove(‘active’);
$(‘#mod .not-active’).addClass(‘active’);
// 推荐
let $mod = $(‘#mod’);
$mod.find(‘.active’).remove(‘active’);
$mod.find(‘.not-active’).addClass(‘active’);
3.页面成分尽量利用事件代理,制止直接事件绑定
利用事件代理能够制止对各样成分都进展绑定,并且能够免止出现内部存款和储蓄器走漏及须要动态添比索素的轩然大波绑定难题,所以尽恐怕不要一直运用事件绑定。
// 不推荐
$(‘.btn’).on(‘click’, function(e){
console.log(this);
});
// 推荐
$(‘body’).on(‘click’, ‘.btn’, function(e){
console.log(this);
});
4.使用touchstart代替click
由于移动端显示屏的安插,touchstart事件和click事件触发时间之内存在300阿秒的延时,所以在页面中并未兑现touchmove滚动处理的情事下,能够使用touchstart事件来代替成分的click事件,加速页面点击的响应速度,升高用户体验。但与此同时大家也要小心页面重叠成分touch动作的点击穿透难题。
// 不推荐
$(‘body’).on(‘click’, ‘.btn’, function(e){
console.log(this);
});
// 推荐
$(‘body’).on(‘touchstart’, ‘.btn’, function(e){
console.log(this);
});
5.制止touchmove、scroll接二连三事件处理
必要对touchmove、scroll那类或许总是触发回调的风浪设置事件节流,例如设置每隔16ms(60帧的帧间隔为16.7ms,由此得以合理地设置为16ms)才实行二次事件处理,幸免频仍的轩然大波调用导致移动端页面卡顿。
// 不推荐
$(‘.scroller’).on(‘touchmove’, ‘.btn’, function(e){
console.log(this);
});
// 推荐
$(‘.scroller’).on(‘touchmove’, ‘.btn’, function(e){
let self = this;
setTimeout(function(){
console.log(self);
}, 16);
});
6.避免使用eval、with,使用join代替连接符+,推荐使用ECMAScript
6的字符串模板。这几个都是局地基础的平安脚本编辑撰写难点,尽可能使用较高效用的表征来形成这么些操作,制止非驴非马或不安全的写法。
7.尽量用到ECMAScript 6+的性状来编制程序
ECMAScript
6+一定水平上更为安全高效,而且部分风味执行进度更快,也是以后正规的供给,所以推举应用ECMAScript
6+的新特色来形成后边的付出。

sourceMap

一般而言在生育环境下的代码是经过webpack包裹后收缩混淆的代码,所以大家恐怕会蒙受那样的难题,如图所示:

4858美高梅 21

我们发现拥有的报错的代码行数都在首先行了,为何吗?那是因为在生产环境下,大家的代码被压缩成了一条龙:

JavaScript

!function(e){var n={};function r(o){if(n[o])return n[o].exports;var
t=n[o]={i:o,l:!1,exports:{}};return
e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){“undefined”!=typeof
Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:”Module”}),Object.defineProperty(e,”__esModule”,{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return
e;if(4&n&&”object”==typeof e&&e&&e.__esModule)return e;var
o=Object.create(null);if(r.r(o),Object.defineProperty(o,”default”,{enumerable:!0,value:e}),2&n&&”string”!=typeof
e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return
o},r.n=function(e){var n=e&&e.__esModule?function(){return
e.default}:function(){return e};return
r.d(n,”a”,n),n},r.o=function(e,n){return
Object.prototype.hasOwnProperty.call(e,n)},r.p=””,r(r.s=0)}([function(e,n){throw
window.onerror=function(e,n,r,o,t){console.log(“errorMessage:
“+e),console.log(“scriptURI: “+n),console.log(“lineNo:
“+r),console.log(“columnNo: “+o),console.log(“error: “+t);var
l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var
u=new
XMLHttpRequest;u.open(“post”,”/middleware/errorMsg”,!0),u.setRequestHeader(“Content-Type”,”application/json”),u.send(JSON.stringify(l))}},new
Error(“那是1个荒谬”)}]);

1
!function(e){var n={};function r(o){if(n[o])return n[o].exports;var t=n[o]={i:o,l:!1,exports:{}};return e[o].call(t.exports,t,t.exports,r),t.l=!0,t.exports}r.m=e,r.c=n,r.d=function(e,n,o){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(r.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var t in e)r.d(o,t,function(n){return e[n]}.bind(null,t));return o},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},r.p="",r(r.s=0)}([function(e,n){throw window.onerror=function(e,n,r,o,t){console.log("errorMessage: "+e),console.log("scriptURI: "+n),console.log("lineNo: "+r),console.log("columnNo: "+o),console.log("error: "+t);var l={errorMessage:e||null,scriptURI:n||null,lineNo:r||null,columnNo:o||null,stack:t&&t.stack?t.stack:null};if(XMLHttpRequest){var u=new XMLHttpRequest;u.open("post","/middleware/errorMsg",!0),u.setRequestHeader("Content-Type","application/json"),u.send(JSON.stringify(l))}},new Error("这是一个错误")}]);

在自家的支出进度中也境遇过这些难点,作者在支付3个效用组件库的时候,使用npm link了本身的机件库,不过由于组件库被npm link后是包装后的生产条件下的代码,全部的报错都固定到了第③行。

化解办法是翻开webpacksource-map,大家利用webpack包裹后的扭转的一份.map的剧本文件就能够让浏览器对错误地点展开追踪了。此处能够参照webpack
document。

实际就是webpack.config.js中增进一行devtool: 'source-map',如下所示,为示范的webpack.config.js

JavaScript

var path = require(‘path’); module.exports = { devtool: ‘source-map’,
mode: ‘development’, entry: ‘./client/index.js’, output: { filename:
‘bundle.js’, path: path.resolve(__dirname, ‘client’) } }

1
2
3
4
5
6
7
8
9
10
var path = require(‘path’);
module.exports = {
    devtool: ‘source-map’,
    mode: ‘development’,
    entry: ‘./client/index.js’,
    output: {
        filename: ‘bundle.js’,
        path: path.resolve(__dirname, ‘client’)
    }
}

webpack包装后转变对应的source-map,那样浏览器就可知稳定到具体错误的职分:

4858美高梅 22

开启source-map的老毛病是包容性,近年来只有Chrome浏览器和Firefox浏览器才对source-map辅助。不过我们对这一类意况也有消除办法。能够行使引入npm库来支撑source-map,可以参照mozilla/source-map。这个npm库既能够运作在客户端也得以运转在服务端,可是更为推荐的是在服务端使用Node.js对吸收到的日志音信时使用source-map解析,防止止源代码的败露导致风险,如下代码所示:

JavaScript

const express = require(‘express’); const fs = require(‘fs’); const
router = express.Router(); const sourceMap = require(‘source-map’);
const path = require(‘path’); const resolve = file =>
path.resolve(__dirname, file); // 定义post接口 router.get(‘/error/’,
async function(req, res) { // 获取前端传过来的报错对象 let error =
JSON.parse(req.query.error); let url = error.scriptULacrosseI; // 压缩文件路径
if (url) { let fileUrl = url.slice(url.indexOf(‘client/’)) + ‘.map’; //
map文件路径 // 解析sourceMap let consumer = await new
sourceMap.SourceMapConsumer(fs.readFileSync(resolve(‘../’ + fileUrl),
‘utf8’)); // 重临3个promise对象 // 解析原始报错数据 let result =
consumer.originalPositionFor({ line: error.lineNo, // 压缩后的行号
column: error.columnNo // 压缩后的列号 }); console.log(result); } });
module.exports = router;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const express = require(‘express’);
const fs = require(‘fs’);
const router = express.Router();
const sourceMap = require(‘source-map’);
const path = require(‘path’);
const resolve = file => path.resolve(__dirname, file);
// 定义post接口
router.get(‘/error/’, async function(req, res) {
    // 获取前端传过来的报错对象
    let error = JSON.parse(req.query.error);
    let url = error.scriptURI; // 压缩文件路径
    if (url) {
        let fileUrl = url.slice(url.indexOf(‘client/’)) + ‘.map’; // map文件路径
        // 解析sourceMap
        let consumer = await new sourceMap.SourceMapConsumer(fs.readFileSync(resolve(‘../’ + fileUrl), ‘utf8’)); // 返回一个promise对象
        // 解析原始报错数据
        let result = consumer.originalPositionFor({
            line: error.lineNo, // 压缩后的行号
            column: error.columnNo // 压缩后的列号
        });
        console.log(result);
    }
});
module.exports = router;

正如图所示,大家早就能够见到,在服务端已经成功解析出了切实错误的行号、列号,我们得以经过日记的章程展开记录,达到了前者万分监察和控制的指标。

4858美高梅 23

2.3总括用户可操作

  用户可操作为拥有DOM都分析达成的日子,暗许同以总括domready时间,因为平时会在此时绑定事件操作。对于利用了模块化异步加载的
JS 能够在代码中去主动标记重要 JS 的加载时间,那也是产品目标的总计划办公室法。

  使用jquery中的$(document).ready()便是此意义
window.performance.timing.domInteractive
window.performance.timing.domContentLoaded伊夫ntStart

  总结公式:

performance.timing.domInteractive - performance.timing.navigationStart

  

五、渲染类
1.行使Viewport固定显示屏渲染,能够加快页面渲染内容
诚如认为,在活动端设置Viewport能够加速页面包车型大巴渲染,同时能够制止缩放导致页面重排重绘。在活动端固定Viewport设置的措施如下。

Vue捕获特别

在自己的品类中就碰见这么的题材,使用了js-tracker那般的插件来归并进行全局的拾壹分捕获和日志上报,结果发现大家历来捕获不到Vue零件的格外,查阅资料得知,在Vue中,格外恐怕被Vue自身给try ... catch了,不会流传window.onerror事件触发,那么大家什么样把Vue组件中的格外香港作家联谊会面捕获呢?

使用Vue.config.errorHandler这样的Vue大局配置,能够在Vue点名组件的渲染和观看比赛时期未捕获错误的处理函数。这些处理函数被调用时,可取得错误音信和Vue
实例。

JavaScript

Vue.config.errorHandler = function (err, vm, info) { // handle error //
`info` 是 Vue 特定的错误音讯,比如错误所在的生命周期钩子 // 只在
2.2.0+ 可用 }

1
2
3
4
5
Vue.config.errorHandler = function (err, vm, info) {
  // handle error
  // `info` 是 Vue 特定的错误信息,比如错误所在的生命周期钩子
  // 只在 2.2.0+ 可用
}

React中,能够行使ErrorBoundary零件包蕴业务组件的章程进行尤其捕获,合营React 16.0+新出的componentDidCatch API,可以兑现统一的不胜捕获和日志上报。

JavaScript

class ErrorBoundary extends React.Component { constructor(props) {
super(props); this.state = { hasError: false }; }
componentDidCatch(error, info) { // Display fallback UI this.setState({
hasError: true }); // You can also log the error to an error reporting
service logErrorToMyService(error, info); } render() { if
(this.state.hasError) { // You can render any custom fallback UI return
<h1>Something went wrong.</h1>; } return
this.props.children; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
 
  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });
    // You can also log the error to an error reporting service
    logErrorToMyService(error, info);
  }
 
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}

使用办法如下:

<ErrorBoundary> <MyWidget /> </ErrorBoundary>

1
2
3
<ErrorBoundary>
  <MyWidget />
</ErrorBoundary>

2.4总下载时间

  暗许能够总括onload时间,那样能够总括同步加载的能源总体加载完的耗时。借使页面中设有很多异步渲染,能够将异步渲染全体完事的小时作为总下载时间。

  总括公式:

performance.timing.loadEventStart- performance.timing.navigationStart

   

<meta name=”viewport” content=”width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=no”>
4858美高梅 ,2.幸免各类格局重排重绘
页面包车型地铁重排重绘很耗品质,所以毫无疑问要尽恐怕裁减页面包车型大巴重排重绘,例如页面图片大小变化、成分地点变动等这个情状都会招致重排重绘。
3.使用CSS3动画,开启GPU加速
应用CSS3动画时能够安装transform:
translateZ(0)来拉开移动设备浏览器的GPU图形处理加速,让动画进度更是流畅。
-webkit-transform: translateZ(0);
-ms-transform: translateZ(0);
-o-transform: translateZ(0);
transform: translateZ(0);
4.客观施用Canvas和requestAnimationFrame
分选Canvas或requestAnimationFrame等更敏捷的动画片达成格局,尽量制止使用setTimeout、setInterval等措施来一向处理接二连三动画。
5.SVG代替图片
某些情状下能够考虑选拔SVG代替图片实现动画,因为使用SVG格式内容更小,而且SVG
DOM结构有利于调整。
6.不滥用float
在DOM渲染树生成后的布局渲染阶段,使用float的因素布局计算相比耗品质,所以尽量收缩float的施用,推荐使用一定布局或flex-box弹性布局的法子来促成页面成分布局。
7.不滥用web字体或过多font-size阐明
过多的font-size表明会扩大字体的尺寸总计,而且也不曾须求的。

品质监控

2.5统计api相关

一部分摘自:美团质量分析框架和属性监察和控制平台,并插手部分其他文字

对此总计脚本,须要满意多少个原则:

  • 制止对作业代码的入侵;(独立的脚本)
  • 不影响被衡量的页面包车型大巴属性;(主文书档案加载完成之后,再流入总计脚本收集数据,并且尽量的会师数据请求,减少带宽消耗。)

分明了数据总结脚本的羁绊规范之后,大家从哪里获得这么些数量吧?近来利用的显要途径有:

  • 主文书档案加载速度,利用 Navigation Timing API 取得;

  4858美高梅 24

  4858美高梅 25

  • 静态财富加载速度,利用 Resource Timing API 取得;

  4858美高梅 26

  • 第叁回渲染速度,IE 下用
    msFirstPaint(window.performance.timing.msFirstPaint) 取得,Chrome
    下选择 loadTimes(window.chrome.loadTimes()) 取得,咱们的 Chrome
    浏览器用户占比超越 百分之七十;
  • 文书档案生成速度,则是在后端应用内打点来收获;

对此主文书档案加载速度,大家从微观到微观的做了如此的分解,从上到下的日子流,左侧的随时标记了每一种指标从何地初叶臆想到哪儿甘休,比如,跳转时间 redirect 由 redirectEnd - redirectStart 总计获得,其余的类比:

  4858美高梅 27

 采集主文书档案加载速度的具体做法是:

  • 在主文书档案 load
    从前提供可缓存数据的接口,方便在总括脚本载入前就足以准备数据;
  • 在主文书档案 load
    之后流入数据收集脚本,该脚本加载成功之后会处理全部的数量;
  • 行使 Navigation Timing API 收集总计获得上海图书馆中的指标;
  • 给持有数据打上页面、地理地方、浏览器等标签,方便更细维度的剖析;

对此静态能源的加载速度,大家也做了类似的解释和采集(使用resource timing
API):

  4858美高梅 28

供给尤其提醒的是,假如您采用 CDN 的话,需求让 CDN 服务商加上
Timing-Allow-Origin 的响应头,才能获得静态财富的多寡。

而对此主文档生成速度,我们则开发了质量计算的
Library,在框架级别集成后端性能的日子指标。

  • High Resolution Timing(高精度计时)

该API正式所定义的JavaScript接口能够提供标准到飞秒级的当下光阴,并且不会惨遭系统时钟偏差或调整的影响。对于质量分析来说,精确的度量结果意义重庆大学。

var perf = performance.now();
// console output 439985.4570000316
  • Page Visibility (页面可知性)

经过这一规范,网站开发者能够以编制程序格局分明页面包车型大巴脚下可知状态,从而使网站能够更实惠地动用电源与CPU。

当页面获得或失去大旨时,文档对象的visibilitychange事件便会被触发。

document.addEventListener('visibilitychange', function(event){if(document.hidden){// Page currently hidden.}else{// Page currently visible.}});

这一事件对于了解页面的可见状态十分有用,举例来说,用户可能会同时打开多个浏览器标签,而你希望只在用户显示你的网站页面时才进行某些操作(比如播放一段音频文件、或是执行一段JavaScript动画),就可以通过这一事件进行触发。对于移动设备来说,如果用户在某个标签中打开了你的网站,但正在另一个标签中浏览其它内容时,这一特性能够节省该设备的电池消耗。(虽然对于你的网站性能来说意义不大……)

六 、架构协议类

最简单易行的天性监察和控制

最普遍的性质监察和控制必要则是索要大家总计用户从开头请求页面到具有DOM要素渲染完成的时光,也正是俗称的首屏加载时间,DOM提供了这一接口,监听documentDOMContentLoaded事件与windowload事件可总计页面首屏加载时间即全体DOM渲染时间:

<!DOCTYPE html> <html> <head>
<title></title> <script type=”text/javascript”> //
记录页面加载开头时间 var timerStart = Date.now(); </script>
<!– 加载静态财富,如样式能源 –> </head> <body>
<!– 加载静态JS能源 –> <script type=”text/javascript”>
document.add伊芙ntListener(‘DOMContentLoaded’, function() {
console.log(“DOM 挂载时间: “, Date.now() – timerStart); // 质量日志上报
}); window.add伊夫ntListener(‘load’, function() {
console.log(“全体财富加载成功时间: “, Date.now()-timerStart); //
品质日志上报 }); </script> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
  <title></title>
  <script type="text/javascript">
    // 记录页面加载开始时间
    var timerStart = Date.now();
  </script>
  <!– 加载静态资源,如样式资源 –>
</head>
<body>
  <!– 加载静态JS资源 –>
  <script type="text/javascript">
    document.addEventListener(‘DOMContentLoaded’, function() {
      console.log("DOM 挂载时间: ", Date.now() – timerStart);
      // 性能日志上报
    });
    window.addEventListener(‘load’, function() {
      console.log("所有资源加载完成时间: ", Date.now()-timerStart);
      // 性能日志上报
    });
  </script>
</body>
</html>

对此利用框架,如Vue或者说React,组件是异步渲染然后挂载到DOM的,在页面开始化时并不曾太多的DOM节点,能够参照下文至于首屏时间采访自动化的化解方案来对渲染时间展开行贿。

其余一些API成效简介

  • Resource
    Timing(财富计时)——对单个能源(如图片)的计时,能够对细粒度的用户体验实行检测。
  • Performance
    Timeline(质量时间线)——以3个联合的接口获取由Navigation
    Timing、Resourcing Timing和User Timing所搜集的质量数据。
  • Battery
    Status(电池状态)——能够检查和测试当前设施的电池组状态,例如是或不是正在充电、电量等级等等。可以依照当下电量决定是不是出示某个内容(例如摄像、动画等等),对于移动装备来说尤其实用。
  • User
    Timing(用户计时)——能够对某段代码、函数实行自定义计时,以理解这段代码的具体运作时刻,类似于stop
    watch的成效。
  • Beacon(灯塔)——能够将分析结果或确诊代码发送给服务器,它利用了异步执行的情势,因而不会影响页面中别的轮代理公司码的周转。对于收集测试结果并拓展总括分析来说是一种非凡方便人民群众的工具。
  • Animation
    Timing(动画计时) –
    通过requestAnimationFrame函数让浏览器精通地控制动画的帧数,能够行得通地同盟显示屏的刷新率,提供更平整的卡通效果,收缩对CPU和电池的消耗。
  • Resource Hits(能源提醒) –
    通过html属性内定财富的预加载,例如在浏览相册时亦可先行加载下一张图片,加快翻页的显得速度。
  • Frame
    Timing(帧计时)——通过2个接口获取与帧相关的习性数据,例如每秒帧数和TTF。该标准如今从不被援救。
  • Navigation Error
    Logging(导航错误日志记录)——通过3个接口存款和储蓄及得到与有个别文书档案的导航相关的不当记录。该标准最近一直不被援助。

 

浏览器帮忙

下表列举了当下主流浏览器对质量API的支撑,个中标注星号的内容并非来自于Web质量工作小组。

规范 Internet Explorer Firefox Chrome Safari Opera iOS Safari Android
Navigation Timing 9 31 全部 8 26 8 (不包括 8.1) 4.1
High Resolution Timing 10 31 全部 8 26 8 (不包括 8.1) 4.4
Page Visibility 10 31 全部 7 26 7.1 4.4
Resource Timing 10 34 全部 26 4.4
Battery Status* 31 (部分支持) 38 26
User Timing 10 全部 26 4.4
Beacon 31 39 26
Animation Timing 10 31 全部 6.1 26 7.1 4.4
Resource Hints 仅限Canary版
Frame Timing
Navigation Error Logging
WebP* 全部 26 4.1
Picture element and srcset attribute * 38 26

其它

DZone.com在《Performance & Monitoring
贰零壹陆》这份白皮书中特地介绍了质量API以及W3C所推荐的新说道、标准及HTML成分,并提供了简便的演示。可以在这里下载完整的白皮书(须要登记)。本文中的示例代码即发源于该白皮书。

若果想打听有关Web质量API的越多内容,能够参照W3C官方文书档案或这篇博客。

 

1.尝试利用SPDY和HTTP 2
在尺度允许的状态下能够考虑选用SPDY协议来开始展览文件财富传输,利用接二连三复用加快传输进度,收缩能源加载时间。HTTP
2在今后也是足以考虑尝试的。
2.应用后端数据渲染
接纳后端数据渲染的艺术可以加速页面内容的渲染突显,防止空白页面包车型大巴产出,同时能够缓解移动端页面SEO的难点。假诺条件允许,后端数据渲染是二个很正确的推行思路。前边的章节会详细介绍后端数据渲染的连锁内容。
3.运用Native View代替DOM的属性逆风局
能够品味使用Native View的MNV开发格局来防止HTML
DOM质量慢的标题,近来应用MNV的支出形式已经足以将页面内容渲染体验做到类似客户端Native应用的心得了。

performance

但是上述时间的督察过于简短,例如大家想总括文书档案的互连网加载耗费时间、解析DOM的耗费时间与渲染DOM的耗费时间,就不太好办到了,所幸的是浏览器提供了window.performance接口,具体可知MDN文档

4858美高梅 29

大约拥有浏览器都帮忙window.performance接口,上边来看望在控制台打字与印刷window.performance能够拿走些什么:

4858美高梅 30

能够看看,window,performance重要包含有memorynavigationtiming以及timeOriginonresourcetimingbufferfull方法。

  • navigation对象提供了在钦命的年月段里产生的操作相关音信,包含页面是加载依然刷新、发生了不怎么次重定向等等。
  • timing对象涵盖延迟相关的属性消息。那是大家页面加载质量优化要求中重庆大学反映的相关新闻。
  • memoryChrome累加的3个非标准化准扩大,那特个性提供了叁个得以获得到骨干内部存款和储蓄器使用处境的靶子。在别的浏览器应该考虑到那个API的万分处理。
  • timeOrigin则赶回品质度量起来时的年华的高精度时间戳。如图所示,精确到了小数点后四位。
  • onresourcetimingbufferfull措施,它是一个在resourcetimingbufferfull事件触发时会被调用的event handler。那些事件当浏览器的能源时间质量缓冲区已满时会触发。能够通过监听这一事变触发来预估页面crash,总括页面crash可能率,以便中期的属性优化,如下示例所示:
JavaScript

function buffer\_full(event) { console.log("WARNING: Resource Timing
Buffer is FULL!"); performance.setResourceTimingBufferSize(200); }
function init() { // Set a callback if the resource buffer becomes
filled performance.onresourcetimingbufferfull = buffer\_full; }
&lt;body onload="init()"&gt;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-6">
6
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-7">
7
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee161383152889-8">
8
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee161383152889-9">
9
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee161383152889-1" class="crayon-line">
function buffer_full(event) {
</div>
<div id="crayon-5b8f00bfee161383152889-2" class="crayon-line crayon-striped-line">
  console.log(&quot;WARNING: Resource Timing Buffer is FULL!&quot;);
</div>
<div id="crayon-5b8f00bfee161383152889-3" class="crayon-line">
  performance.setResourceTimingBufferSize(200);
</div>
<div id="crayon-5b8f00bfee161383152889-4" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f00bfee161383152889-5" class="crayon-line">
function init() {
</div>
<div id="crayon-5b8f00bfee161383152889-6" class="crayon-line crayon-striped-line">
  // Set a callback if the resource buffer becomes filled
</div>
<div id="crayon-5b8f00bfee161383152889-7" class="crayon-line">
  performance.onresourcetimingbufferfull = buffer_full;
</div>
<div id="crayon-5b8f00bfee161383152889-8" class="crayon-line crayon-striped-line">
}
</div>
<div id="crayon-5b8f00bfee161383152889-9" class="crayon-line">
&lt;body onload=&quot;init()&quot;&gt;
</div>
</div></td>
</tr>
</tbody>
</table>

2.6 品质优化分为七个等级来做

  1.用到测试工具自测和优化(工具如ySlow/,线上中国人民解放军海军事工业程高校业具www.webpagetest.org、Ali测、gtmetrix)

  ySlow/ShowSlow: 【前端品质监察和控制种类,前端品质目标数据呈现,无法兑现自动化监察和控制用户实际的采用场景,针对移动端的质量监察和控制,最近由于其自作者正视的工具绝超越53%只有PC端,在运动端缺少相应的数量反映工具(尤其是活动端本身错综复杂的网络环境),所以假使想使用ShowSlow作为前端品质监察和控制平台,要求单独实现数据搜集系统,而只是将ShowSlow当作来得系统使用,开源】

  Page Speed:
【基于一密密麻麻优化规则对网站开始展览检查和测试,类似的有Yslow(推荐使用 】  

  Ali测:基于WebPageTest,网页前端品质测试工具;  

  PhantomJS:自动化监测,模拟Phantom JS 是三个服务器端的 JavaScript
API 的 Web基特,基于它能够轻松完成 web
自动化测试。类似的有berserkJS。可是都以服务器模拟测试,无法监察和控制用户真正环境。

 

  webpagetest线上版

  4858美高梅 31

  4858美高梅 32

  基于WebPagetest的Ali测(已下线,不举例了,上17测:

  综合了pagespeed和ySlow的GTmetrix

4858美高梅 33

 

  2.启用线上监督用户真实际情状形(前端质量监察和控制平台)

  看多少个例证

  透视宝:
【前端质量上报,图表展现,监察和控制用户真正的采纳场景,付费】  

  4858美高梅 34

 

  4858美高梅 35

  提供了每多个伸手的详细音讯

  4858美高梅 36

  4858美高梅 37

  4858美高梅 38

 

  能够按选用的字段排序,通过过滤实行类似数据比较,能够查阅每二个伸手的详细音讯,可是按url搜索貌似没有用,假诺这么些有效的话那就足以对同贰个页面做时间的对照。

  4858美高梅 39

  

  优点:

  1.柱状岁月线排列

  2.多少个目的同时显示,便于比较

  缺点:

  1.不够部分首要时刻(白屏时间=首字节时间+HTML下载实现时间+底部财富加载时间)

  2.质量没有按地区分类,参考价值大大收缩

  3.免费版本只存款和储蓄3天

 

  Browser Insight:
【前端质量上报,图表突显,监察和控制用户实际的运用场景,付费】

  4858美高梅 40

 

  4858美高梅 41

  4858美高梅 42

  4858美高梅 43

  

  4858美高梅 44

  要翻看某次访问的详情须求在云快照中拍照,模拟访问

  4858美高梅 45

  4858美高梅 46

   优点:

  1.指标齐全

  2.慢加载追踪全体能源加载情形

  缺点:

  1.五个性能指标没有按地区分类的数量,参考价值大大缩小

   

  mmtrix(质量魔方):

  先看评测

   WEB评测实例:总结数据不错

  4858美高梅 47

 

  4858美高梅 48

  真实用户质量监察和控制:

  4858美高梅 49

  4858美高梅 50

  4858美高梅 51

  4858美高梅 52

  优点:

  1.支撑分裂地域的多个至关心珍惜要品质指标的来得

  2.扶助显得差异距离的数量比例

  缺点:

  1.不支持https协议

 

  还有二个境内较大的属性监察和控制平台听云

  4858美高梅 53

  目的比价少,没有太多价值。就不做相比较了。

 

 

 

  看一下国外的性质量监督控网站 

  先看newrelic(rpm.newrelic.com),注册必要协调行使外网代理

  4858美高梅 54

  和OneAPM很像,前端质量指标不全。用来监控ajax请求,
js报错等还不易,可是知足不断小编的要求。

 

  appdynamics(www.appdynamics.com)

  注册居然找不到中华

  4858美高梅 55

  随便选了三个canmroon

  4858美高梅 56

   和透视宝很像。免费版本保存时间更少,唯有24钟头。

 

   总的来说,mmtrix和OneAPM目的更全有的。还尚未切磋他们的监督检查代码,不掌握监察和控制的指标正确与否。公司的脾气那块也刚运行,离优良还有十分大学一年级段距离,就写到那里了,希望对商量品质刚起步的童鞋有点效用,任务还很重,加油。

  原文链接:

正文章摘要自书籍《现代前端技术分析》。

计量网站品质

使用performancetiming品质,能够得到页面质量相关的数目,那里在重重篇章都有关系有关利用window.performance.timing记录页面质量的篇章,例如alloyteam团体写的初探
performance –
监察和控制网页与程序质量,对于timing的各项质量含义,能够依靠摘自此文的下图精通,以下代码摘自此文作为计量网站品质的工具函数参考:

4858美高梅 57

JavaScript

// 获取 performance 数据 var performance = { // memory
是非标准化准属性,只在 Chrome 有 // 财富难点:小编有多少内部存款和储蓄器 memory: {
usedJSHeapSize: 16100000, // JS
对象(包罗V8引擎内部对象)占用的内部存储器,一定小于 totalJSHeapSize
totalJSHeapSize: 35一千00, // 可利用的内部存款和储蓄器 jsHeapSizeLimit: 79两千000 //
内部存款和储蓄器大小限制 }, // 农学难题:小编从哪里来? navigation: { redirectCount:
0, // 即便有重定向的话,页面通过三遍重定向跳转而来 type: 0 // 0 即
TYPE_NAVIGATENEXT 符合规律进入的页面(非刷新、非重定向等) // 1 即
TYPE_RELOAD 通过 window.location.reload() 刷新的页面 // 2 即
TYPE_BACK_FOENVISIONWA奇骏D 通过浏览器的前行后退按钮进入的页面(历史记录) //
255 即 TYPE_UNDEFINED 非上述办法进入的页面 }, timing: { //
在同七个浏览器上下文中,前三个网页(与如今页面不必然同域)unload
的时间戳,假若无前1个网页 unload ,则与 fetchStart 值相等
navigationStart: 144111269一九三一, // 前多少个网页(与近期页面同域)unload
的日子戳,如若无前多少个网页 unload 只怕前二个网页与当下页面分化域,则值为
0 unload伊芙ntStart: 0, // 和 unload伊芙ntStart 相对应,再次来到前三个网页
unload 事件绑定的回调函数执行完成的岁月戳 unload伊芙ntEnd: 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
响应全体收到实现的时间(获取到最后2个字节),包含从地面读取缓存
responseEnd: 1441112692687, // 起首解析渲染 DOM 树的日子,此时
Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
domLoading: 1441112692690, // 达成解析 DOM 树的年华,Document.readyState
变为 interactive,并将抛出 readystatechange 相关事件 // 注意只是 DOM
树解析达成,那时候并从未从头加载网页内的财富 domInteractive:
1441112693093, // DOM 解析实现后,网页国内资本源加载发轫的时刻 // 在
DOMContentLoaded 事件抛出前发出 domContentLoaded伊芙ntStart:
1441112693093, // DOM 解析完结后,网页国内资本源加载成功的日子(如 JS
脚本加载执行完结) domContentLoaded伊芙ntEnd: 1441112693101, // DOM
树解析完成,且财富也准备稳妥的年华,Document.readyState 变为
complete,并将抛出 readystatechange 相关事件 domComplete: 1441112693214,
// load 事件发送给文书档案,也即 load 回调函数开首施行的岁月 //
注意要是没有绑定 load 事件,值为 0 load伊夫ntStart: 1441112693214, //
load 事件的回调函数执行完成的时刻 load伊夫ntEnd: 1441112693215 //
字母顺序 // connectEnd: 1441112692155, // connectStart: 1441112692155,
// domComplete: 1441112693214, // domContentLoaded伊芙ntEnd:
1441112693101, // domContentLoadedEventStart: 1441112693093, //
domInteractive: 1441112693093, // domLoading: 1441112692690, //
domainLookupEnd: 1441112692155, // domainLookupStart: 1441112692155, //
fetchStart: 1441112692155, // load伊夫ntEnd: 1441112693215, //
load伊芙ntStart: 1441112693214, // navigationStart: 144111269一九三四, //
redirectEnd: 0, // redirectStart: 0, // requestStart: 1441112692158, //
responseEnd: 1441112692687, // responseStart: 1441112692686, //
secureConnectionStart: 0, // unload伊夫ntEnd: 0, // unload伊夫ntStart: 0 }
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// 获取 performance 数据
var performance = {  
    // memory 是非标准属性,只在 Chrome 有
    // 财富问题:我有多少内存
    memory: {
        usedJSHeapSize:  16100000, // JS 对象(包括V8引擎内部对象)占用的内存,一定小于 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 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
        navigationStart: 1441112691935,
        // 前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
        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
        // 字母顺序
        // connectEnd: 1441112692155,
        // connectStart: 1441112692155,
        // domComplete: 1441112693214,
        // domContentLoadedEventEnd: 1441112693101,
        // domContentLoadedEventStart: 1441112693093,
        // domInteractive: 1441112693093,
        // domLoading: 1441112692690,
        // domainLookupEnd: 1441112692155,
        // domainLookupStart: 1441112692155,
        // fetchStart: 1441112692155,
        // loadEventEnd: 1441112693215,
        // loadEventStart: 1441112693214,
        // navigationStart: 1441112691935,
        // redirectEnd: 0,
        // redirectStart: 0,
        // requestStart: 1441112692158,
        // responseEnd: 1441112692687,
        // responseStart: 1441112692686,
        // secureConnectionStart: 0,
        // unloadEventEnd: 0,
        // unloadEventStart: 0
    }
};

 

JavaScript

// 总括加载时间 function getPerformanceTiming() { var performance =
window.performance; if (!performance) { // 当前浏览器不帮助console.log(‘你的浏览器不支持 performance 接口’); return; } var t =
performance.timing; var times = {}; //【主要】页面加载成功的时光
//【原因】那差不多代表了用户等待页面可用的年月 times.loadPage =
t.load伊夫ntEnd – t.navigationStart; //【主要】解析 DOM 树结构的时间
//【原因】反省下您的 DOM 树嵌套是否太多了! times.domReady =
t.domComplete – t.responseEnd; //【主要】重定向的光阴
//【原因】拒绝重定向!比如, 就不应当写成
times.redirect = t.redirectEnd – t.redirectStart;
//【重要】DNS 查询时间 //【原因】DNS
预加载做了么?页面内是或不是运用了太多不一致的域名导致域名查询的年华太长?
// 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5
prefetch]()
times.lookupDomain = t.domainLookupEnd – t.domainLookupStart;
//【主要】读取页面第一个字节的日子
//【原因】那足以通晓为用户获得你的财富占用的时光,加异地机房了么,加CDN
处理了么?加带宽了么?加 CPU 运算速度了么? // TTFB 即 Time To First
Byte 的意趣 //
维基百科: times.ttfb
= t.responseStart – t.navigationStart; //【首要】内容加载成功的命宫//【原因】页面内容通过 gzip 压缩了么,静态财富 css/js 等压缩了么?
times.request = t.responseEnd – t.requestStart; //【主要】执行 onload
回调函数的时间 //【原因】是还是不是太多不须求的操作都放到 onload
回调函数里实施了,考虑过延迟加载、按需加载的策略么? times.load伊芙nt =
t.load伊夫ntEnd – t.load伊芙ntStart; // DNS 缓存时间 times.appcache =
t.domainLookupStart – t.fetchStart; // 卸载页面包车型地铁年华 times.unload伊夫nt
= t.unload伊夫ntEnd – t.unload伊夫ntStart; // TCP 建立连接成功握手的大运times.connect = t.connectEnd – t.connectStart; return times; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 计算加载时间
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 树结构的时间
    //【原因】反省下你的 DOM 树嵌套是不是太多了!
    times.domReady = t.domComplete – t.responseEnd;
    //【重要】重定向的时间
    //【原因】拒绝重定向!比如,http://example.com/ 就不该写成 http://example.com
    times.redirect = t.redirectEnd – t.redirectStart;
    //【重要】DNS 查询时间
    //【原因】DNS 预加载做了么?页面内是不是使用了太多不同的域名导致域名查询的时间太长?
    // 可使用 HTML5 Prefetch 预查询 DNS ,见:[HTML5 prefetch](http://segmentfault.com/a/1190000000633364)            
    times.lookupDomain = t.domainLookupEnd – t.domainLookupStart;
    //【重要】读取页面第一个字节的时间
    //【原因】这可以理解为用户拿到你的资源占用的时间,加异地机房了么,加CDN 处理了么?加带宽了么?加 CPU 运算速度了么?
    // TTFB 即 Time To First Byte 的意思
    // 维基百科:https://en.wikipedia.org/wiki/Time_To_First_Byte
    times.ttfb = t.responseStart – t.navigationStart;
    //【重要】内容加载完成的时间
    //【原因】页面内容经过 gzip 压缩了么,静态资源 css/js 等压缩了么?
    times.request = t.responseEnd – t.requestStart;
    //【重要】执行 onload 回调函数的时间
    //【原因】是否太多不必要的操作都放到 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;
}

日记上报

单身的日志域名

对此日记上报利用单独的日记域名的指标是防止对工作造成影响。其一,对于服务器来说,大家自然不指望占用工作服务器的推测能源,也不期待过多的日记在工作服务器堆积,造成工作服务器的存款和储蓄空间不够的情状。其二,大家驾驭在页面伊始化的经过中,会对页面加载时间、PV、UV等数码实行汇报,这几个反映请求会和加载业务数据差不离是同时刻产生,而浏览器一般会对同三个域名的请求量有并发数的限定,如Chrome会有对并发数为6个的限量。由此要求对日记系统独立设定域名,最小化对页面加载品质造成的影响。

跨域的题材

对于单身的日记域名,肯定会涉嫌到跨域的题目,选择的缓解方案一般有以下三种:

  • 一种是布局空的Image目的的章程,其原因是请求图片并不关乎到跨域的标题;
JavaScript

var url = 'xxx'; new Image().src = url;

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee170123843269-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee170123843269-2">
2
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee170123843269-1" class="crayon-line">
var url = 'xxx';
</div>
<div id="crayon-5b8f00bfee170123843269-2" class="crayon-line crayon-striped-line">
new Image().src = url;
</div>
</div></td>
</tr>
</tbody>
</table>

  • 利用Ajax报告日志,必须对日记服务器接口开启跨域请求底部Access-Control-Allow-Origin:*,这里Ajax就并不强制行使GET伸手了,即可制伏URL长度限制的题材。
JavaScript

if (XMLHttpRequest) { var xhr = new XMLHttpRequest();
xhr.open('post', 'https://log.xxx.com', true); //
上报给node中间层处理 xhr.setRequestHeader('Content-Type',
'application/json'); // 设置请求头
xhr.send(JSON.stringify(errorObj)); // 发送参数 }

<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<tbody>
<tr class="odd">
<td><div class="crayon-nums-content" style="font-size: 13px !important; line-height: 15px !important;">
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-2">
2
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-4">
4
</div>
<div class="crayon-num" data-line="crayon-5b8f00bfee174544186263-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5b8f00bfee174544186263-6">
6
</div>
</div></td>
<td><div class="crayon-pre" style="font-size: 13px !important; line-height: 15px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;">
<div id="crayon-5b8f00bfee174544186263-1" class="crayon-line">
if (XMLHttpRequest) {
</div>
<div id="crayon-5b8f00bfee174544186263-2" class="crayon-line crayon-striped-line">
  var xhr = new XMLHttpRequest();
</div>
<div id="crayon-5b8f00bfee174544186263-3" class="crayon-line">
  xhr.open('post', 'https://log.xxx.com', true); // 上报给node中间层处理
</div>
<div id="crayon-5b8f00bfee174544186263-4" class="crayon-line crayon-striped-line">
  xhr.setRequestHeader('Content-Type', 'application/json'); // 设置请求头
</div>
<div id="crayon-5b8f00bfee174544186263-5" class="crayon-line">
  xhr.send(JSON.stringify(errorObj)); // 发送参数
</div>
<div id="crayon-5b8f00bfee174544186263-6" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

在本身的花色中选用的是第2种的办法,也正是构造空的Image目的,可是大家清楚对于GET呼吁会有长度的限量,要求确定保证的是伸手的长度不会当先阈值。

节约响应主旨

对此大家汇报日志,其实对于客户端的话,并不要求考虑上报的结果,甚至对于举报失利,大家也不供给在前者做其余交互,所以报告来说,其实选择HEAD伸手就够了,接口再次回到空的结果,最大地减小上报日志造成的财富浪费。

统一反映

好像于7-Up图的思维,假使大家的应用供给报告的日记数量很多,那么有要求合并日志进行统一的举报。

消除方案能够是尝尝在用户距离页面大概零部件销毁时发送三个异步的POST请求来拓展反馈,但是尝试在卸载(unload)文书档案从前向web服务器发送数据。保险在文书档案卸载时期发送数据一贯是2个辛勤。因为用户代理平时会忽视在卸载事件处理器中发出的异步XMLHttpRequest,因为那时早已会跳转到下二个页面。所以这里是必须设置为共同的XMLHttpRequest请求吗?

JavaScript

window.add伊夫ntListener(‘unload’, logData, false); function logData() {
var client = new XMLHttpRequest(); client.open(“POST”, “/log”, false);
// 第4个参数申明是联合的 xhr client.setRequestHeader(“Content-Type”,
“text/plain;charset=UTF-8”); client.send(analyticsData); }

1
2
3
4
5
6
7
8
window.addEventListener(‘unload’, logData, false);
 
function logData() {
    var client = new XMLHttpRequest();
    client.open("POST", "/log", false); // 第三个参数表明是同步的 xhr
    client.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");
    client.send(analyticsData);
}

使用同步的法门势必会对用户体验造成影响,甚至会让用户感受到浏览器卡死感到,对于产品而言,体验十二分倒霉,通过查阅MDN文档,能够行使sendBeacon()方法,将会使用户代理在有机遇时异步地向服务器发送数据,同时不会推迟页面包车型地铁卸载或影响下一导航的载入品质。那就化解了付出分析数据时的装有的标题:使它可相信,异步并且不会潜移默化下一页面的加载。别的,代码实际上还要比其余技术简单!

上面包车型大巴例证体现了一个抵触上的总结代码格局——通过动用sendBeacon()方法向服务器发送数据。

JavaScript

window.addEventListener(‘unload’, logData, false); function logData() {
navigator.sendBeacon(“/log”, analyticsData); }

1
2
3
4
5
window.addEventListener(‘unload’, logData, false);
 
function logData() {
    navigator.sendBeacon("/log", analyticsData);
}

小结

作为前端开发者而言,要对产品保持敬畏之心,时刻保持对质量追求极致,对充裕不可忍受的姿态。前端的性质监察和控制与尤其申报显得尤其关键。

代码难免有标题,对于那么些能够利用window.onerror或者addEventListener的章程充足全局的相当捕获侦听函数,但或然利用那种措施不或然正确捕获到错误:对于跨域的台本,必要对script标签扩张二个crossorigin=”anonymous”;对于生产环境打包的代码,不恐怕正分明位到尤其产生的行数,能够运用source-map来化解;而对于利用框架的情事,需求在框架统一的不胜捕获处埋点。

而对于品质的监察和控制,所幸的是浏览器提供了window.performance API,通过这么些API,很省心地赢获得日前页面质量相关的数码。

而那个相当和总体性数据怎么着反馈呢?一般说来,为了幸免对作业产生的熏陶,会单独建立日志服务器和日志域名,但对于差异的域名,又会时有发生跨域的标题。大家得以经过结构空的Image目的来化解,亦只怕通过设定跨域请求底部Access-Control-Allow-Origin:*来化解。别的,假如申报的性质和日志数据高频触发,则足以在页面unload时统一举报,而unload时的异步请求又恐怕会被浏览器所忽视,且不可能改为共同请求。此时navigator.sendBeacon API可算帮了我们大忙,它可用于通过HTTP将少量数据异步传输到Web服务器。而忽略页面unload时的熏陶。

1 赞 1 收藏
评论

4858美高梅 58

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有