Del: Network timing

This commit is contained in:
surunzi
2017-12-15 21:00:56 +08:00
parent ea1656ec1b
commit 75424b9954
7 changed files with 39 additions and 316 deletions

View File

@@ -28,10 +28,7 @@ Console for Mobile Browsers.
## Why
Logging things out on mobile browser is never an easy stuff. I used to include
`window onerror alert` script inside pages to find out JavaScript errors, kind
of stupid and inefficient. Desktop browser DevTools is great, and I wish there
is a similar one on mobile side, which leads to the creation of Eruda.
Logging things out on mobile browser is never an easy stuff. I used to include `window onerror alert` script inside pages to find out JavaScript errors, kind of stupid and inefficient. Desktop browser DevTools is great, and I wish there is a similar one on mobile side, which leads to the creation of Eruda.
## Demo
@@ -49,7 +46,7 @@ javascript:(function () { var script = document.createElement('script'); script.
* [Console](doc/TOOL_API.md#console): Display JavaScript logs.
* [Elements](doc/TOOL_API.md#elements): Check dom state.
* [Network](doc/TOOL_API.md#network): Show performance timing, ajax requests status.
* [Network](doc/TOOL_API.md#network): Show ajax requests status.
* [Resource](/doc/TOOL_API.md#resources): Show localStorage, cookie information.
* [Info](doc/TOOL_API.md#info): Show url, user agent info.
* [Snippets](doc/TOOL_API.md#snippets): Include snippets used most often.
@@ -77,10 +74,7 @@ It's also available on [jsDelivr](http://www.jsdelivr.com/projects/eruda) and [c
<script>eruda.init();</script>
```
The JavaScript file size is quite huge(about 90kb gzipped) and therefore not
suitable to include in mobile pages. It's recommended to make sure eruda is
loaded only when eruda is set to true on url(http://example.com/?eruda=true),
for example:
The JavaScript file size is quite huge(about 90kb gzipped) and therefore not suitable to include in mobile pages. It's recommended to make sure eruda is loaded only when eruda is set to true on url(http://example.com/?eruda=true), for example:
```javascript
;(function () {
@@ -111,14 +105,13 @@ eruda.init({
## Plugins
It is possible to enhance Eruda with more features by writing plugins. Check
source code of plugins below to learn how to write your own custom tool panels.
It is possible to enhance Eruda with more features by writing plugins. Check source code of plugins below to learn how to write your own custom tool panels.
* [eruda-fps](https://github.com/liriliri/eruda-fps): Display page fps info.
* [eruda-features](https://github.com/liriliri/eruda-features): Browser feature detections.
* [eruda-timing](https://github.com/liriliri/eruda-timing): Show performance and resource timing.
When writing plugins, you can use utilities exposed by Eruda, see
[docs](doc/UTIL_API.md) here.
When writing plugins, you can use utilities exposed by Eruda, see [docs](doc/UTIL_API.md) here.
## Contribution

View File

@@ -32,7 +32,7 @@ Eruda 是一个专为手机网页前端设计的调试面板,类似 DevTools
3. Elements面板查看标签内容及属性查看应用在Dom上的样式支持页面元素高亮支持屏幕直接点击选取查看Dom上绑定的各类事件。
4. Network面板图表显示页面加载速度查看页面各资源请求时间Android捕获XHR请求查看发送数据、返回头、返回内容等信息。
4. Network面板捕获XHR请求查看发送数据、返回头、返回内容等信息。
5. Resources面板查看并清除localStorage、sessionStorage及cookie查看页面加载脚本及样式文件查看页面加载图片。

View File

@@ -89,15 +89,7 @@ elements.set(document.body);
## Network
Display performance timing, resource timing and xhr requests.
### Config
|Name |Type |Desc |
|------------------|-------|--------------------------|
|disablePerformance|boolean|Disable Performance Timing|
|hideXhrResource |boolean|Hide Xhr Resource Timing |
|overrideXhr |boolean|Catch Xhr Requests |
Display xhr requests.
## Resources

View File

@@ -1,70 +1,23 @@
{{#if timing}}
<div class="eruda-performance-timing">
<div class="eruda-inner-wrapper">
{{#each data}}
<div class="eruda-bar">
<span style="position:relative;left:{{start}}%;width:{{len}}%">{{name}}({{duration}}ms)</span>
</div>
{{/each}}
</div>
<div class="eruda-title">
Request
<div class="eruda-btn eruda-clear-xhr">
<span class="eruda-icon-ban"></span>
</div>
<div class="eruda-performance-timing-data">
<table>
<thead>
<tr>
<th>Name</th>
<th>Time(ms)</th>
</tr>
</thead>
<tbody>
{{#each timing}}
<tr>
<td>{{@key}}</td>
<td>{{this}}</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
{{/if}}
{{#if entries}}
<div class="eruda-title">ResourceTiming</div>
<ul class="eruda-entries">
{{#each entries}}
<li class="eruda-entry" data-idx="{{@index}}">
</div>
<ul class="eruda-requests">
{{#if requests}}
{{#each requests}}
<li class="eruda-request {{#if hasErr}}eruda-error{{/if}}" data-id="{{@key}}">
<span>{{name}}</span>
<span>{{initiatorType}}</span>
<span>{{status}}</span>
<span>{{method}}</span>
<span>{{subType}}</span>
<span>{{size}}</span>
<span>{{displayTime}}</span>
<span class="eruda-blue">{{url}}</span>
</li>
{{/each}}
</ul>
{{/if}}
{{#if displayReq}}
<div class="eruda-title">
XMLHttpRequest
<div class="eruda-btn eruda-clear-xhr">
<span class="eruda-icon-ban"></span>
</div>
</div>
<ul class="eruda-requests">
{{#if requests}}
{{#each requests}}
<li class="eruda-request {{#if hasErr}}eruda-error{{/if}}" data-id="{{@key}}">
<span>{{name}}</span>
<span>{{status}}</span>
<span>{{method}}</span>
<span>{{subType}}</span>
<span>{{size}}</span>
<span>{{displayTime}}</span>
<span class="eruda-blue">{{url}}</span>
</li>
{{/each}}
{{else}}
<li><span>Empty</span></li>
{{/if}}
</ul>
{{/if}}
{{else}}
<li><span>Empty</span></li>
{{/if}}
</ul>

View File

@@ -12,14 +12,8 @@ export default class Network extends Tool
this._style = util.evalCss(require('./Network.scss'));
this.name = 'network';
this._performanceTimingData = [];
this._performanceTiming = {};
this._resourceTimingData = [];
this._requests = {};
this._tpl = require('./Network.hbs');
let performance = this._performance = window.webkitPerformance || window.performance;
this._hasResourceTiming = performance && util.isFn(performance.getEntries);
}
init($el, container)
{
@@ -27,7 +21,6 @@ export default class Network extends Tool
this._container = container;
this._bindEvent();
this._initCfg();
}
show()
{
@@ -125,10 +118,7 @@ export default class Network extends Tool
let self = this;
$el.on('click', '.eruda-performance-timing', function ()
{
$el.find('.eruda-performance-timing-data').show();
}).on('click', '.eruda-request', function ()
$el.on('click', '.eruda-request', function ()
{
let id = util.$(this).data('id'),
data = self._requests[id];
@@ -143,15 +133,6 @@ export default class Network extends Tool
subType: data.subType,
resHeaders: data.resHeaders
});
}).on('click', '.eruda-entry', function ()
{
let idx = util.$(this).data('idx'),
data = self._resourceTimingData[Number(idx)];
if (data.initiatorType === 'img')
{
showSources('img', data.url);
}
}).on('click', '.eruda-clear-xhr', function ()
{
self._requests = {};
@@ -168,99 +149,6 @@ export default class Network extends Tool
container.showTool('sources');
}
}
_getPerformanceTimingData()
{
let performance = this._performance;
if (!performance) return;
let timing = performance.timing;
if (!timing) return;
let data = [];
/* eslint-disable no-unused-vars */
let {
navigationStart,
unloadEventStart,
unloadEventEnd,
redirectStart,
redirectEnd,
fetchStart,
domainLookupStart,
domainLookupEnd,
connectStart,
connectEnd,
secureConnectionStart,
requestStart,
responseStart,
responseEnd,
domLoading,
domInteractive,
domContentLoadedEventStart,
domContentLoadedEventEnd,
domComplete,
loadEventStart,
loadEventEnd
} = timing;
let start = navigationStart,
end = loadEventEnd,
total = end - start;
function getData(name, startTime, endTime)
{
let duration = endTime - startTime;
return {
name: name,
start: (startTime - start) / total * 100,
duration: duration,
len: duration / total * 100
};
}
data.push(getData('Total', navigationStart, loadEventEnd));
data.push(getData('Network/Server', navigationStart, responseStart));
data.push(getData('App Cache', fetchStart, domainLookupStart));
data.push(getData('DNS', domainLookupStart, domainLookupEnd));
data.push(getData('TCP', connectStart, connectEnd));
data.push(getData('Time to First Byte', requestStart, responseStart));
data.push(getData('Response', responseStart, responseEnd));
data.push(getData('Unload', unloadEventStart, unloadEventEnd));
data.push(getData('DOM Processing', domLoading, domComplete));
data.push(getData('DOM Construction', domLoading, domInteractive));
this._performanceTimingData = data;
let performanceTiming = {};
[
'navigationStart',
'unloadEventStart',
'unloadEventEnd',
'redirectStart',
'redirectEnd',
'fetchStart',
'domainLookupStart',
'domainLookupEnd',
'connectStart',
'connectEnd',
'secureConnectionStart',
'requestStart',
'responseStart',
'responseEnd',
'domLoading',
'domInteractive',
'domContentLoadedEventStart',
'domContentLoadedEventEnd',
'domComplete',
'loadEventStart',
'loadEventEnd'
].forEach((val) =>
{
performanceTiming[val] = timing[val] === 0 ? 0 : timing[val] - start;
});
this._performanceTiming = performanceTiming;
}
destroy()
{
super.destroy();
@@ -268,77 +156,13 @@ export default class Network extends Tool
util.evalCss.remove(this._style);
this.restoreXhr();
}
_getResourceTimingData()
{
if (!this._hasResourceTiming) return;
let entries = this._performance.getEntries(),
hideXhr = this.config.get('hideXhrResource'),
data = [];
entries.forEach(entry =>
{
if (hideXhr && entry.initiatorType === 'xmlhttprequest') return;
data.push({
name: util.getFileName(entry.name),
displayTime: formatTime(entry.duration),
url: entry.name,
initiatorType: entry.initiatorType
});
});
this._resourceTimingData = data;
}
_initCfg()
{
let cfg = this.config = Settings.createCfg('network', {
disablePerformance: false,
hideXhrResource: true,
overrideXhr: true
});
if (cfg.get('overrideXhr')) this.overrideXhr();
cfg.on('change', (key, val) =>
{
switch (key)
{
case 'overrideXhr': return val ? this.overrideXhr() : this.restoreXhr();
}
});
let settings = this._container.get('settings');
settings.text('Network')
.switch(cfg, 'overrideXhr', 'Catch Xhr Requests');
if (this._hasResourceTiming) settings.switch(cfg, 'hideXhrResource', 'Hide Xhr Resource Timing');
settings.switch(cfg, 'disablePerformance', 'Disable Performance Timing')
.separator();
}
_render()
{
if (!this.active) return;
let cfg = this.config;
let renderData = {};
this._getResourceTimingData();
let renderData = {entries: this._resourceTimingData};
if (cfg.get('overrideXhr'))
{
renderData.displayReq = true;
if (!util.isEmpty(this._requests)) renderData.requests = this._requests;
}
if (!cfg.get('disablePerformance'))
{
util.ready(() => this._getPerformanceTimingData());
renderData.data = this._performanceTimingData;
renderData.timing = this._performanceTiming;
}
if (!util.isEmpty(this._requests)) renderData.requests = this._requests;
this._renderHtml(this._tpl(renderData));
}

View File

@@ -4,57 +4,13 @@
.dev-tools { .tools {
.network {
@include overflow-auto(y);
.performance-timing {
padding: $padding 0;
.inner-wrapper {
background: $blue;
.bar {
@include overflow-auto(x);
border-bottom: 1px solid #fff;
span {
font-size: $font-size-s;
white-space: nowrap;
color: #fff;
padding: 5px 0;
background: $red;
display: inline-block;
}
&:last-child {
border-bottom: none;
}
}
}
}
.performance-timing-data {
padding-bottom: $padding;
text-align: center;
display: none;
table {
width: 100%;
background: #fff;
border-collapse: collapse;
text-align: left;
th {
background: $gray;
text-align: left;
color: #fff;
font-size: $font-size;
}
td {
font-size: $font-size-s;
}
th, td {
padding: 10px;
}
}
}
.title {
@include right-circle-btn();
background: $gray;
padding: $padding;
color: #fff;
}
.requests, .entries {
.requests {
background: #fff;
border-bottom: 1px solid $gray-light;
margin-bottom: 10px;
@@ -82,9 +38,5 @@
}
}
}
.entries {
@include overflow-auto(y);
max-height: 200px;
}
}
} }

View File

@@ -67,6 +67,14 @@ export default [
},
desc: 'Browser feature detections'
},
{
name: 'Load Timing Plugin',
fn()
{
loadPlugin('timing');
},
desc: 'Show performance and resource timing'
},
{
name: 'Restore Settings',
fn()
@@ -162,5 +170,6 @@ function loadPlugin(name)
let pluginVersion = {
fps: '1.0.2',
features: '1.0.2'
features: '1.0.2',
timing:'1.0.0'
};