Reference link
https://developers.google.com/web/tools/chrome-devtools/evaluate-performance
Just another site
选择 network tool
上图可以看出,
<html>
<head>
<title>Critical Path: Measure Async</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link href="style.css" rel="stylesheet">
</head>
<body onload="measureCRP()">
<p>Hello <span>web performance</span> students!</p>
<div><img src="awesome-photo.jpg"></div>
<script async src="timing.js"></script>
</body>
</html>
JavaScript 可能会查询 CSSOM, 所以在加载 link stylesheet 解析css 时会阻止后面的js 执行, DOMContentLoaded 事件 就需要等待link完全加载才触发
效果好多了!解析 HTML 之后不久即会触发 domContentLoaded 事件;浏览器已得知不要阻止 JavaScript,并且由于没有其他阻止解析器的脚本,CSSOM 构建也可同步进行了。 不需要等到css 加载完成
清单文件可以具有任何名称,但通常是manifest.webmanifest从根目录(您网站的顶级目录)来命名 和提供的。
{
"short_name": "Weather",
"name": "Weather: Do I need an umbrella?",
"description": "Weather forecast information",
"icons": [
{
"src": "/images/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/images/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6",
"shortcuts": [
{
"name": "How's weather today?",
"short_name": "Today",
"description": "View weather information for today",
"url": "/today?source=pwa",
"icons": [{ "src": "/images/today.png", "sizes": "192x192" }]
},
{
"name": "How's weather tomorrow?",
"short_name": "Tomorrow",
"description": "View weather information for tomorrow",
"url": "/tomorrow?source=pwa",
"icons": [{ "src": "/images/tomorrow.png", "sizes": "192x192" }]
}
]
}
您必须至少提供short_name或name属性。如果同时提供了两者,short_name则在用户的主屏幕,启动器或其他空间可能受限的地方使用。name在安装应用程序时使用。
对于Chrome,您必须至少提供192×192像素的图标和512×512像素的图标
要使用 可屏蔽图标(有时在Android上称为自适应图标),您还需要添加”purpose”: “any maskable”到 icon属性
并告诉在那里,当它启动你的应用程序应该启动浏览器
注意: 如果用户单击应用程序中位于之外 scope的链接,则该链接将在现有PWA窗口中打开并呈现。如果要在浏览器选项卡中打开链接,则必须添加target=”_blank” 到 a 标签中。在Android设备上,与的链接target="_blank"
将在Chrome自定义标签中打开
标签添加到Progressive Web App的所有页面
<link rel="manifest" href="/manifest.webmanifest">
1. 用户卸载网页的时候,有时需要向服务器发一些数据。很自然的做法是在unload事件或beforeunload事件的监听函数里面,使用XMLHttpRequest对象发送数据。但是,这样做不是很可靠,因为XMLHttpRequest对象是异步发送,很可能在它即将发送的时候,页面已经卸载了,从而导致发送取消或者发送失败。
上报数据的方法
1. 我们可以将 ajax 请求改为同步方法,这样就能保证请求一定能发送到服务端。由于 fetch 及 axios 都不支持同步请求,所以需要通过 XMLHttpRequest 发送同步请求。这里要注意的是,将请求改为同步以后,会阻塞页面关闭或重新加载的过程,这样就会影响用户体验。
2. 动态图片
我们可以通过在 beforeunload 事件处理器中创建一个图片元素并设置它的 src 属性的方法来延迟卸载以保证数据的发送,因为绝大多数浏览器会延迟卸载以保证图片的载入,所以数据可以在卸载事件中发送。
[cc lang=”js”]const reportData = (url, data) => {
let img = document.createElement(‘img’);
const params = [];
Object.keys(data).forEach((key) => {
params.push(`${key}=${encodeURIComponent(data[key])}`);
});
img.onload = () => img = null;
img.src = `${url}?${params.join(‘&’)}`;[/cc]
此时服务端可以返回一个 1px * 1px 的图片,保证触发 img 的 onload 事件,但如果某些浏览器在实现上无法保证图片的载入,就会导致上报数据的丢失。
3. sendBeacon
为了解决上述问题,便有了 navigator.sendBeacon 方法,使用该方法发送请求,可以保证数据有效送达,且不会阻塞页面的卸载或加载,并且编码比起上述方法更加简单。
navigator.sendBeacon(url, data);
url 就是上报地址,data 可以是 ArrayBufferView
,Blob
,DOMString
或 Formdata
,根据官方规范,需要 request header 为 CORS-safelisted-request-header,在这里则需要保证 Content-Type
为以下三种之一:
application/x-www-form-urlencoded
multipart/form-data
text/plain
如果数据类型是 string,则可以直接上报,此时该请求会自动设置请求头的 Content-Type 为 text/plain。
[cc lang=”js”]const reportData = (url, data) => {
navigator.sendBeacon(url, data);
}[/cc]
如果用 Blob 发送数据,这时需要我们手动设置 Blob 的 MIME type,一般设置为 application/x-www-form-urlencoded。
[cc lang=”js”]const reportData = (url, data) => {
const blob = new Blob([JSON.stringify(data), {
type: ‘application/x-www-form-urlencoded’,
}]);
navigator.sendBeacon(url, blob);
};[/cc]
可以直接创建一个新的 Formdata,此时该请求会自动设置请求头的 Content-Type 为 multipart/form-data
[cc lang=”js”]const reportData = (url, data) => {
const formData = new FormData();
Object.keys(data).forEach((key) => {
let value = data[key];
if (typeof value !== ‘string’) {
// formData只能append string 或 Blob
value = JSON.stringify(value);
}
formData.append(key, value);
});
navigator.sendBeacon(url, formData);
};[/cc]
Performance是一个做前端性能监控离不开的API,最好在页面完全加载完成之后再使用,因为很多值必须在页面完全加载之后才能得到。最简单的办法是在window.onload事件中读取各种数据。
按触发顺序排列所有属性:(更详细标准的解释请参看:W3C Editor’s Draft)
navigationStart
:在同一个浏览器上下文中,前一个网页(与当前页面不一定同域)unload 的时间戳,如果无前一个网页 unload ,则与 fetchStart 值相等
unloadEventStart
:前一个网页(与当前页面同域)unload 的时间戳,如果无前一个网页 unload 或者前一个网页与当前页面不同域,则值为 0
unloadEventEnd
:和 unloadEventStart 相对应,返回前一个网页 unload 事件绑定的回调函数执行完毕的时间戳
redirectStart
:第一个 HTTP 重定向发生时的时间。有跳转且是同域名内的重定向才算,否则值为 0
redirectEnd
:最后一个 HTTP 重定向完成时的时间。有跳转且是同域名内的重定向才算,否则值为 0
fetchStart
:浏览器准备好使用 HTTP 请求抓取文档的时间,这发生在检查本地缓存之前
domainLookupStart
:DNS 域名查询开始的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
domainLookupEnd
:DNS 域名查询完成的时间,如果使用了本地缓存(即无 DNS 查询)或持久连接,则与 fetchStart 值相等
connectStart
:HTTP(TCP) 开始建立连接的时间,如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接开始的时间
connectEnd
:HTTP(TCP) 完成建立连接的时间(完成握手),如果是持久连接,则与 fetchStart 值相等,如果在传输层发生了错误且重新建立连接,则这里显示的是新建立的连接完成的时间
注意:这里握手结束,包括安全连接建立完成、SOCKS 授权通过
secureConnectionStart
:HTTPS 连接开始的时间,如果不是安全连接,则值为 0
requestStart
:HTTP 请求读取真实文档开始的时间(完成建立连接),包括从本地读取缓存,连接错误重连时,这里显示的也是新建立连接的时间
responseStart
:HTTP 开始接收响应的时间(获取到第一个字节),包括从本地读取缓存
responseEnd
:HTTP 响应全部接收完成的时间(获取到最后一个字节),包括从本地读取缓存
domLoading
:开始解析渲染 DOM 树的时间,此时 Document.readyState 变为 loading,并将抛出 readystatechange 相关事件
domInteractive
:完成解析 DOM 树的时间,Document.readyState 变为 interactive,并将抛出 readystatechange 相关事件
!!!只是 DOM 树解析完成,这时候并没有开始加载网页内的资源
domContentLoadedEventStart
:DOM 解析完成后,网页内资源加载开始的时间,文档发生 DOMContentLoaded事件的时间
domContentLoadedEventEnd
:DOM 解析完成后,网页内资源加载完成的时间(如 JS 脚本加载执行完毕),文档的DOMContentLoaded 事件的结束时间
domComplete
:DOM 树解析完成,且资源也准备就绪的时间,Document.readyState 变为 complete,并将抛出 readystatechange 相关事件
loadEventStart
:load 事件发送给文档,也即 load 回调函数开始执行的时间,如果没有绑定 load 事件,值为 0
loadEventEnd
:load 事件的回调函数执行完毕的时间,如果没有绑定 load 事件,值为 0
常用计算:
DNS查询耗时 :domainLookupEnd – domainLookupStart
TCP链接耗时 :connectEnd – connectStart
request请求耗时 :responseEnd – responseStart
解析dom树耗时 : domComplete – domInteractive
白屏时间 :responseStart – navigationStart
domready时间(用户可操作时间节点) :domContentLoadedEventEnd – navigationStart
onload时间(总下载时间) :loadEventEnd – navigationStart
performance.now()是当前时间与performance.timing.navigationStart的时间差,以微秒(百万分之一秒)为单位的时间,与 Date.now()-performance.timing.navigationStart的区别是不受系统程序执行阻塞的影响,因此更加精准
阻止浏览器回退
$(function() {
if (window.history && window.history.pushState) {
$(window).on(‘popstate’, function () {
window.history.pushState(‘forward’, null, ‘#’);
window.history.forward(1);
});
}
window.history.pushState(‘forward’, null, ‘#’); //在IE中必须得有这两行
window.history.forward(1);
})
看每秒的帧数, 如果FPS 是红线说明 用户不到60FPS
解决问题
看summary 扇形图 看看哪个时间长 然后减少它的时间
.moving-element {
will-change: transform;
}
.moving-element {
transform: translateZ(0);
}