mirror of
https://github.com/liriliri/eruda.git
synced 2026-03-20 09:38:37 +08:00
Del: Network timing
This commit is contained in:
19
README.md
19
README.md
@@ -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
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ Eruda 是一个专为手机网页前端设计的调试面板,类似 DevTools
|
||||
|
||||
3. Elements面板:查看标签内容及属性;查看应用在Dom上的样式;支持页面元素高亮;支持屏幕直接点击选取;查看Dom上绑定的各类事件。
|
||||
|
||||
4. Network面板:图表显示页面加载速度;查看页面各资源请求时间(Android);捕获XHR请求,查看发送数据、返回头、返回内容等信息。
|
||||
4. Network面板:捕获XHR请求,查看发送数据、返回头、返回内容等信息。
|
||||
|
||||
5. Resources面板:查看并清除localStorage、sessionStorage及cookie;查看页面加载脚本及样式文件;查看页面加载图片。
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
@@ -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'
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user