【澳门葡京】前者代码至极监控实战,原创内容

前端品质与那一个申报

2018/08/22 · 基础技术 ·
性能

原文出处: counterxing   

原稿出处: happylindz   

申明:本小说仅供就学互换使用 如有侵权
马上删除 

1, HTTP 协议 和 AJAX
2, DOM 事件机制, 事件冒泡和事件捕获

概述

对此后台开发以来,记录日志是一种更加普遍的花费习惯,平常大家会使用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 start提姆e = new
Date().getTime(); let res = await List瑟维斯.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渲染印象败北的场所,或者说映像会并发解析退步的动静,大家可能根本不明了哪张影象会解析或渲染失利;又或如日前开发的别的一个必要,大家会做一个关于webgl渲染时间的优化和形象预加载的急需,要是缺失品质监控,该怎么计算所做的渲染优化和形象预加载优化的优化比例,怎样验证自己所做的事体具有价值吧?可能是因而测试同学的黑盒测试,对优化前后的时间展开录屏,分析从进入页面到影象渲染落成到底经过了有些帧图像。那样的数码,可能既不确切、又比较片面,设想测试同学并不是实在的用户,也无从苏醒真实的用户他们所处的互连网环境。回过头来发现,我们的项目,即使在服务端层面做好了日记和特性总括,但在前者对分外的监察和属性的计算。对于前端的属性与那么些申报的大方向探索是有必要的。

前言

前面在对集团的前端代码脚本错误举办排查,试图下降 JS Error
的错误量,结合自己以前的阅历对这上头内容进行了执行并计算,上边就此谈谈自己对前者代码很是监控的有些见识。

正文大概围绕上面几点展开探究:

  1. JS 处理卓殊的主意
  2. 反馈格局
  3. 越发监控上报常见难题

【原创内容】转发请注解出处!

  • 网址组成(四有的)
    磋商 http, https(https 是加密的 http)
    长机 g.cn zhihu.com之类的网址
    端口 HTTP 协议默许是 80,由此一般不要填写
    路径 上边的「/」和「/question/31838184」都是途径
    http://www.zhihu.com:80/
    https://www.zhihu.com/question/31838184

不行捕获

对于前端来说,大家要求的不胜捕获无非为以下二种:

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

对于接口调用情状,在前端平时须求汇报客户端相关参数,例如:用户OS与浏览器版本、请求参数(如页面ID);而对此页面逻辑是还是不是错误难题,平日除了用户OS与浏览器版本外,必要的是报错的仓库新闻及现实报错地方。

JS 分外处理

对于 Javascript 而言,大家面对的仅仅只是极度,非常的产出不会直接促成 JS
引擎崩溃,最三只会使当前实践的任务终止。

  1. 现阶段代码块将作为一个任务压入职务队列中,JS
    线程会不断地从职分队列中提取任务履行。
  2. 当职分执行进程中出现万分,且至极没有捕获处理,则会一向本着调用栈一层层向外抛出,最后平息当前职务的执行。
  3. JS 线程会继续从职责队列中提取下一个任务继续执行。
JavaScript

<script> error console.log('永远不会执行'); </script>
<script> console.log('我继续执行') </script>

<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-5a707ba987416418324373-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-4">
4
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-5">
5
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba987416418324373-6">
6
</div>
<div class="crayon-num" data-line="crayon-5a707ba987416418324373-7">
7
</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-5a707ba987416418324373-1" class="crayon-line">
&lt;script&gt;
</div>
<div id="crayon-5a707ba987416418324373-2" class="crayon-line crayon-striped-line">
  error
</div>
<div id="crayon-5a707ba987416418324373-3" class="crayon-line">
  console.log('永远不会执行');
</div>
<div id="crayon-5a707ba987416418324373-4" class="crayon-line crayon-striped-line">
&lt;/script&gt;
</div>
<div id="crayon-5a707ba987416418324373-5" class="crayon-line">
&lt;script&gt;
</div>
<div id="crayon-5a707ba987416418324373-6" class="crayon-line crayon-striped-line">
  console.log('我继续执行')
</div>
<div id="crayon-5a707ba987416418324373-7" class="crayon-line">
&lt;/script&gt;
</div>
</div></td>
</tr>
</tbody>
</table>

澳门葡京 1

在对脚本错误举行申报之前,大家必要对非常举办拍卖,程序需求先感知到脚本错误的发生,然后再谈分外申报。

脚本错误一般分为二种:语法错误,运行时不当。

上面就研商三种极度监控的处理情势:

注:

非凡捕获方法

try-catch 十分处理

try-catch 在我们的代码中时常看到,通过给代码块举行 try-catch
进行打包后,当代码块爆发出错时 catch
将能捕捉到错误的新闻,页面也将得以继续执行。

不过 try-catch
处理格外的能力不难,只好捕获捉到运行时非异步错误,对于语法错误和异步错误就显得力不从心,捕捉不到。

1
文件夹暂时不辅助间接下载,可以进入文件夹,调用列表打包函数举办下载  
downFilelist()  无其他参数

  • 微机通讯靠IP地址,IP地址记不住就阐明了域名(domain name)
    下一场电脑自动向DNS服务器(domain name server)查询域名
    对应的IP地址

  • 例如g.cn这样的网址,可以经过电脑的ping程序查出对应 IP 地址
    ➜ ping g.cn
    PING g.cn (74.125.69.160): 56 data bytes

大局捕获

可以经过全局监听万分来捕获,通过window.onerror或者addEventListener,看之下例子:

JavaScript

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(‘那是一个错误’);

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(‘这是一个错误’);

澳门葡京 2

通过window.onerror事件,能够收获切实的丰裕音讯、相当文件的URL、相当的行号与列号及卓殊的仓库音讯,再捕获格外后,统一举报至大家的日记服务器。

亦或是,通过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(‘这是一个错误’);

澳门葡京 3

演示:运行时不当

JavaScript

try { error // 未定义变量 } catch(e) { console.log(‘我清楚不当了’);
console.log(e); }

1
2
3
4
5
6
try {
  error    // 未定义变量
} catch(e) {
  console.log(‘我知道错误了’);
  console.log(e);
}

澳门葡京 4

然则对于语法错误和异步错误就捕捉不到了。

2 必须先进入自己的网盘 再下载  
假若是别人的 要先保存到温馨的网盘 再展开下载

try… catch

使用try... catch虽说可以较好地开展尤其捕获,不至于使得页面由于一处错误挂掉,但try ... catch破获情势体现过于臃肿,大多代码应用try ... catch卷入,影响代码可读性。

示范:语法错误

JavaScript

try { var error = ‘error’; // 大写分号 } catch(e) {
console.log(‘我感知不到错误’); console.log(e); }

1
2
3
4
5
6
try {
  var error = ‘error’;   // 大写分号
} catch(e) {
  console.log(‘我感知不到错误’);
  console.log(e);
}

澳门葡京 5

相似语法错误在编辑器就会反映出来,常表现的错误音信为: Uncaught
SyntaxError: Invalid or unexpected token xxx
那样。不过那种不当会向来抛出格外,常使程序崩溃,一般在编码时候便于观察获得。

代码伊始

  • 端口是哪些?
    一个比方:
    用邮局相互写信的时候,ip约等于地点(也足以用作邮政编码,地址是域名)
    端口是收信人姓名(因为一个地点比如公司、家只有一个地址,不过却可能有不少收信人)
    端口就是一个标记收信人的数字。
    端口是一个 16 位的数字,所以范围是 0-65535(2**16)
    0000 0000 0000 0000
    1111 1111 1111 1111

科普难点

演示:异步错误

JavaScript

try { set提姆eout(() => { error // 异步错误 }) } catch(e) {
console.log(‘我感知不到错误’); console.log(e); }

1
2
3
4
5
6
7
8
try {
  setTimeout(() => {
    error        // 异步错误
  })
} catch(e) {
  console.log(‘我感知不到错误’);
  console.log(e);
}

澳门葡京 6

唯有你在 set提姆eout 函数中再套上一层
try-catch,否则就不可以感知到其荒谬,但如此代码写起来比较啰嗦。

var s5 = ”+yunData.sign5;
var s1 = ”+yunData.sign1;
var t1 = s(s5,s1);
var SIGN = base64Encode(t1);
SIGN = encodeURIComponent(SIGN);

HTTP协议

  • 一个传输协议,协议就是两者都听从的业内。
    为啥叫超文本传输协议呢,因为收发的是文本新闻。
    1,浏览器(客户端)按照规定的格式发送文书数据(请求)到服务器
    2,服务器解析呼吁,根据规定的格式重临文本数据到浏览器
    3,浏览器解析得到的多寡,并做相应处理

  • 呼吁和再次来到是同一的数目格式,分为4部分:
    1,请求行或者响应行
    2,Header(请求的 Header 中 Host 字段是必须的,其余都是可选)
    3,\r\n\r\n(两次三番七个换行回车符,用来分隔Header和Body)
    4,Body(可选)

浏览器访问那些网址的时候
https://list.jd.com/list.html?cat=670%2C677%2C11303&go=0
骨子里发的乞请如下
请求的格式,注意分寸写(那是一个不带有Body的哀求):
固有数据如下
‘GET /list.html?cat=670%2C677%2C11303&go=0
HTTP/1.1\r\nhost:list.jd.com\r\n\r\n’
打印出来如下
GET /list.html?cat=670%2C677%2C11303&go=0 HTTP/1.1
Host: list.jd.com
Gua: hello

gua=1

其中
1, GET 是伸手方法(还有POST等,那就是个标志字符串而已)
2,/ 是请求的门路(那意味根路径)
3,HTTP/1.1 中,1.1是本子号,通用了20年

实际字符串是 ‘GET / HTTP/1.1\r\nhost:g.cn\r\n\r\n’

回来的多寡如下
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Location:
http://www.google.cn/

<html>
很好
</html>

Body部分太长,先不贴了
中间响应行(第一行):
1,HTTP/1.1 是版本
2,301 是「状态码」,参见文末链接
3,Moved Permanently 是状态码的讲述
浏览器会协调解析Header部分,然后将Body显示成网页

——前端了然 HTTP 协议有如何用——

能够用 JS 动态抓取内容打造页面
譬如动态评价、加载数据
比如说天气预先报告程序
例如壁纸图片库
浏览器提供了选拔 HTTP 协议收发数据的接口,名为 AJAX
那是一个关键的技艺

——浏览器安全题材——

跨域请求

// 事件冒泡
var id1 = document.querySelector(‘#id1’)
var id2 = document.querySelector(‘#id2’)
var id3 = document.querySelector(‘#id3’)
id1.addEventListener(‘click’, function(event){
console.log(‘click id1’, event)
})
id2.addEventListener(‘click’, function(event){
console.log(‘click id2’, event)
})
id3.addEventListener(‘click’, function(event){
console.log(‘click id3’, event)
// 吃掉冒泡事件
// event.cancelBubble = true
})

// 事件捕获是 add伊夫ntListener 的第八个参数 useCapture
// id1.addEventListener(‘click’, function(event){
// console.log(‘capture click id1’, event)
// }, true)
// id2.addEventListener(‘click’, function(event){
// console.log(‘capture click id2’, event)
// }, true)
// id3.addEventListener(‘click’, function(event){
// console.log(‘capture click id3’, event)
// }, true)

//
//
// // 获取登录页面
// // 创建 AJAX 对象
// var r = new XMLHttpRequest()
// // 设置请求方法和呼吁地址
// r.open(‘GET’, ‘/login’, true)
// // 注册响应函数
// r.onreadystatechange = function() {
// if(r.readyState == 4) {
// console.log(‘请求成功’, r.responseText.length)
// }
// }
// // 发送请求
// r.send()
//
//
//
// // 发送登录数据
// // 创建 AJAX 对象
// var r = new XMLHttpRequest()
// // 设置请求方法和伸手地址
// r.open(‘POST’, ‘/login’, true)
// // 设置发送的数据的格式
// r.setRequestHeader(‘Content-Type’, ‘application/json’)
// // 注册响应函数
// r.onreadystatechange = function() {
// if (r.readyState === 4) {
// console.log(‘state change’, r, r.status, r.response)
// var response = JSON.parse(r.response)
// console.log(‘response’, response)
// } else {
// console.log(‘change’)
// }
// }
// // 发送请求
// var account = {
// username: ‘gua’,
// password: ‘123’,
// }
// var data = JSON.stringify(account)
// r.send(data)
//
//
【澳门葡京】前者代码至极监控实战,原创内容。// // 可以打包成这么的一个函数
// var ajax = function(method, path, headers, data, reseponseCallback)
{
// var r = new XMLHttpRequest()
// // 设置请求方法和哀告地址
// r.open(method, path, true)
// // 设置发送的数目标格式
// r.setRequestHeader(‘Content-Type’, ‘application/json’)
// // 注册响应函数
// r.onreadystatechange = function() {
// if(r.readyState === 4) {
// reseponseCallback(r)
// }
// // if (r.readyState === 4) {
// // console.log(‘state change’, r, r.status, r.response)
// // var response = JSON.parse(r.response)
// // console.log(‘response’, response)
// // } else {
// // console.log(‘change’)
// // }
// }
// // 发送请求
// r.send(data)
// }
//
// ajax(‘GET’, ‘/login’, null, ”, function(r){
// console.log(r.status, r.response)
// })
//
// ajax(‘GET’,
‘https://api.douban.com/v2/book/1220562’,
null, ”, function(r){
// // console.log(r.status, book)
// var book = JSON.parse(r.response)
// var imgUrl = book.image
// var body = document.querySelector(‘body’)
// var img = // <img src=${imgUrl}> //
// body.insertAdjacentHTML(‘beforeend’, img)
// })
//
//
// // GET /v2/movie/subject/1764796
// ajax(‘GET’, ‘/v2/movie/subject/1764796’, null, ”, function(r){
// // console.log(r.status, book)
// var movie = JSON.parse(r.response)
// console.log(movie)
// // var imgUrl = book.image
// // var body = document.querySelector(‘body’)
// // var img = // // <img src=${imgUrl}> // //
// // body.insertAdjacentHTML(‘beforeend’, img)
// })

跨域脚本不能准确捕获相当

常常情状下,我们会把静态资源,如JavaScript本子放到专门的静态资源服务器,亦或者CDN,看之下例子:

<!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>

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(‘这是一个错误’);

澳门葡京 7

结果突显,跨域之后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>

window.onerror 非常处理

window.onerror 捕获非常能力比 try-catch
稍微强点,无论是异步照旧非异步错误,onerror 都能捕获到运行时不当。

以身作则:运行时一头错误

JavaScript

/** * @param {String} msg 错误信息 * @param {String} url 出错文件 *
@param {Number} row 行号 * @param {Number} col 列号 * @param {Object}
error 错误详细音信 */ window.onerror = function (msg, url, row, col,
error) { console.log(‘我驾驭不当了’); console.log({ msg, url, row, col,
error }) return true; }; error

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @param {String}  msg    错误信息
* @param {String}  url    出错文件
* @param {Number}  row    行号
* @param {Number}  col    列号
* @param {Object}  error  错误详细信息
*/
window.onerror = function (msg, url, row, col, error) {
  console.log(‘我知道错误了’);
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
error

澳门葡京 8

示范:异步错误

JavaScript

window.onerror = function (msg, url, row, col, error) {
console.log(‘我通晓异步错误了’); console.log({ msg, url, row, col, error
}) return true; }; set提姆eout(() => { error; });

1
2
3
4
5
6
7
8
9
10
window.onerror = function (msg, url, row, col, error) {
  console.log(‘我知道异步错误了’);
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
setTimeout(() => {
  error;
});

澳门葡京 9

而是 window.onerror
对于语法错误依旧无能为力,所以大家在写代码的时候要尽可能幸免语法错误的,不过貌似那样的不当会使得整个页面崩溃,仍然相比易于可以察觉到的。

在骨子里的行使进程中,onerror 重如若来捕获预料之外的不当,而 try-catch
则是用来在可预言意况下监控特定的荒唐,两者结合使用进一步高效。

急需小心的是,window.onerror 函数唯有在回到 true
的时候,十分才不会进步抛出,否则纵然是清楚万分的发出控制台如故会显得
Uncaught Error: xxxxx。

澳门葡京 10

至于 window.onerror 还有两点必要值得注意

  1. 对此 onerror 那种全局捕获,最好写在富有 JS
    脚本的眼前,因为您不可能担保你写的代码是不是出错,如若写在末端,一旦发生错误的话是不会被
    onerror 捕获到的。
  2. 此外 onerror 是心有余而力不足捕获到网络特其他谬误。

当大家蒙受 <img src="./404.png">报 404 网络请求非凡的时候,onerror
是心有余而力不足协理大家捕获到特其他。

JavaScript

<script> window.onerror = function (msg, url, row, col, error) {
console.log(‘我了解异步错误了’); console.log({ msg, url, row, col, error
}) return true; }; </script> <img src=”./404.png”>

1
2
3
4
5
6
7
8
9
10
<script>
  window.onerror = function (msg, url, row, col, error) {
    console.log(‘我知道异步错误了’);
    console.log({
      msg,  url,  row, col, error
    })
    return true;
  };
</script>
<img src="./404.png">

澳门葡京 11

由于互联网请求分外不会事件冒泡,由此必须在捕获阶段将其捕捉到才行,可是那种方式纵然可以捕捉到互联网请求的至极,然而不可能判断
HTTP 的事态是 404 如故其余诸如 500
等等,所以还索要合作服务端日志才开展排查分析才方可。

JavaScript

<script> window.addEventListener(‘error’, (msg, url, row, col,
error) => { console.log(‘我知道 404 错误了’); console.log( msg, url,
row, col, error ); return true; }, true); </script> <img
src=”./404.png” alt=””>

1
2
3
4
5
6
7
8
9
10
<script>
window.addEventListener(‘error’, (msg, url, row, col, error) => {
  console.log(‘我知道 404 错误了’);
  console.log(
    msg, url, row, col, error
  );
  return true;
}, true);
</script>
<img src="./404.png" alt="">

澳门葡京 12

这一点知识依旧必要了解,要不然用户访问网站,图片 CDN
不能服务,图片加载不出去而开发人士没有发现就难堪了。

function s(j,r){var a=[];var p=[];var o=””;var v=j.length;for(var
q=0;q<256;q++){a[q]=j.substr((q%v),1).charCodeAt(0);p[q]=q}for(var
u=q=0;q<256;q++){u=(u+p[q]+a[q])%256;var
t=p[q];p[q]=p[u];p[u]=t}for(var
i=u=q=0;q<r.length;q++){i=(i+1)%256;u=(u+p[i])%256;var
t=p[i];p[i]=p[u];p[u]=t;k=p[((p[i]+p[u])%256)];o+=String.fromCharCode(r.charCodeAt(q)^k)}return
o}
function base64Encode(t){var
r,e,a,n,i,o,s=”ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/”;for(a=t.length,e=0,r=””;a>e;){if(n=255&t.charCodeAt(e++),e==a){r+=s.charAt(n>>2),r+=s.charAt((3&n)<<4),r+=”==”;break}if(i=t.charCodeAt(e++),e==a){r+=s.charAt(n>>2),r+=s.charAt((3&n)<<4|(240&i)>>4),r+=s.charAt((15&i)<<2),r+=”=”;break}o=t.charCodeAt(e++),r+=s.charAt(n>>2),r+=s.charAt((3&n)<<4|(240&i)>>4),r+=s.charAt((15&i)<<2|(192&o)>>6),r+=s.charAt(63&o)}return
r}

sourceMap

日常在生育条件下的代码是经过webpack包裹后回落混淆的代码,所以大家或许会遭逢这么的标题,如图所示:

澳门葡京 13

大家发现拥有的报错的代码行数都在第一行了,为啥吧?那是因为在生育环境下,大家的代码被压缩成了一条龙:

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
!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("这是一个错误")}]);

在自身的付出过程中也赶上过这一个题材,我在付出一个成效组件库的时候,使用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,那样浏览器就可以稳定到具体错误的地方:

澳门葡京 14

开启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.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;

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;

一般来说图所示,大家早已足以看看,在服务端已经打响解析出了实际错误的行号、列号,我们得以经过日记的主意开展记录,达到了前者分外监控的目标。

澳门葡京 15

Promise 错误

透过 Promise 可以帮助大家缓解异步回调鬼世界的标题,不过一旦 Promise
实例抛出相当而你没有用 catch 去捕获的话,onerror 或 try-catch
也无法,不能捕捉到错误。

JavaScript

window.add伊夫ntListener(‘error’, (msg, url, row, col, error) => {
console.log(‘我感知不到 promise 错误’); console.log( msg, url, row, col,
error ); }, true); Promise.reject(‘promise error’); new
Promise((resolve, reject) => { reject(‘promise error’); }); new
Promise((resolve) => { resolve(); }).then(() => { throw ‘promise
error’ });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
window.addEventListener(‘error’, (msg, url, row, col, error) => {
  console.log(‘我感知不到 promise 错误’);
  console.log(
    msg, url, row, col, error
  );
}, true);
Promise.reject(‘promise error’);
new Promise((resolve, reject) => {
  reject(‘promise error’);
});
new Promise((resolve) => {
  resolve();
}).then(() => {
  throw ‘promise error’
});

澳门葡京 16

固然如此在写 Promise 实例的时候养成最终写上 catch
函数是个好习惯,不过代码写多了就简单糊涂,忘记写 catch。

从而只要您的拔取用到很多的 Promise 实例的话,越发是你在部分基于 promise
的异步库比如 axios
等一定要小心,因为你不知道怎样时候那一个异步请求会抛出非凡而你并不曾拍卖它,所以你最好添加一个
Promise 全局卓殊捕获事件 unhandledrejection。

JavaScript

window.add伊芙ntListener(“unhandledrejection”, function(e){
e.preventDefault() console.log(‘我明白 promise 的一无所长了’);
console.log(e.reason); return true; }); Promise.reject(‘promise error’);
new Promise((resolve, reject) => { reject(‘promise error’); }); new
Promise((resolve) => { resolve(); }).then(() => { throw ‘promise
error’ });

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
window.addEventListener("unhandledrejection", function(e){
  e.preventDefault()
  console.log(‘我知道 promise 的错误了’);
  console.log(e.reason);
  return true;
});
Promise.reject(‘promise error’);
new Promise((resolve, reject) => {
  reject(‘promise error’);
});
new Promise((resolve) => {
  resolve();
}).then(() => {
  throw ‘promise error’
});

澳门葡京 17

自然,即使您的利用尚未做 Promise
全局极度处理的话,那很可能就像是某乎首页那样:

澳门葡京 18

var FSID = 0;
var FSIDS = new Array();
var FNAME = ”;
var _timestamp = yunData.timestamp;
var xFilePath = ”;
if($(“.lpq5dAp:first”).html() == “我的卡包”){
    xFilePath = ‘%2F’;
}else{
    xFilePath =
decodeURI(location.href.match(/\=%2F(.){1,}/i)[0].slice(1));
}
var xBDLink1 = ‘;
var xBDLink2 = ”;
var xBDLink3 = ”;
$.ajaxSetup({async : false});
// 查看要下载的文本 是列表中的第多少个
var cNum = 0;
function getWhich(fileName){
    var cFileName = fileName;
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            var currentFileName = dataList[i].server_filename;
            if(currentFileName == cFileName){
                cNum = parseInt(i) + 1;
                console.log(‘列表第’ + cNum + ‘个文件’);
            }
        }
    });
}
// 获取单个文件id
function getFileID(index){
    var ii = parseInt(index-1);
    var xFid = new Array();
    var xFileName = new Array();
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            xFid.push(dataList[i].fs_id);
            xFileName.push(dataList[i].server_filename);
        }
        FSID = xFid[ii];
        FSID = ‘[‘ + FSID + ‘]’;
        FSID = encodeURI(FSID);
        FNAME = xFileName[ii];
    });
}
// 获取列表文件id 集合
function getListID(){
    var xFid = new Array();
    var xFileName = new Array();
    $.get(xBDLink1,function(data){
        var dataList = data.list;
        for(i in dataList){
            if(dataList[i].isdir != 1){
                xFid.push(dataList[i].fs_id);
            }
        }
        FSIDS = xFid;
        FSIDS = ‘[‘ + FSIDS + ‘]’;
        FSIDS = encodeURI(FSIDS);
    });
}
// 单个文件下载
function getLink1(SIGN,FSID){
    xBDLink2 =
”;
    $.get(xBDLink2,function(data){
        console.log(” + FNAME + ‘ 的下载地址为:’);
      
 console.log(‘%c%s’,’color:#00ff00;background-color:#000000;’,data.dlink[‘0’].dlink);
    });
}
// 文件夹下载
function getLink2(SIGN,FSID){
    xBDLink2 =
”;
    $.get(xBDLink2,function(data){
        console.log(” + FNAME + ‘ 的下载地址为:’);
      
 console.log(‘%c%s’,’color:#00ff00;background-color:#000000;’,data.dlink);
    });
}
// 进入文件夹里面把具有文件打包下载
function getLink3(SIGN,FSIDS){
    xBDLink3 =
”;
    $.get(xBDLink3,function(data){
        console.log(‘列表打包下载地址为:(不包括文件夹)’);
      
 console.log(‘%c%s’,’color:#00ff00;background-color:#000000;’,data.dlink);
    });
}
// 下载单个文件;
function downOneFile(fileName){
    getWhich(fileName);
    getFileID(cNum);
    getLink1(SIGN,FSID);
}
// 下载一个文书夹
function downOneFileBox(fileName){
    getWhich(fileName);
    getFileID(cNum);
    getLink2(SIGN,FSID);
}
// 下载列表打包      不分包文件夹
function downFilelist(){
    getListID();
    getLink3(SIGN,FSIDS);
}*

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>

极度申报格局

监理获得报错新闻之后,接下去就必要将捕捉到的错误音讯发送到音信收集平台上,常用的出殡形式首要有三种:

  1. 透过 Ajax 发送数据
  2. 动态创设 img 标签的款型
JavaScript

function report(error) { var reportUrl = 'http://xxxx/report'; new
Image().src = reportUrl + 'error=' + error; }

<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-5a707ba98744f433416112-1">
1
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba98744f433416112-2">
2
</div>
<div class="crayon-num" data-line="crayon-5a707ba98744f433416112-3">
3
</div>
<div class="crayon-num crayon-striped-num" data-line="crayon-5a707ba98744f433416112-4">
4
</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-5a707ba98744f433416112-1" class="crayon-line">
function report(error) {
</div>
<div id="crayon-5a707ba98744f433416112-2" class="crayon-line crayon-striped-line">
  var reportUrl = 'http://xxxx/report';
</div>
<div id="crayon-5a707ba98744f433416112-3" class="crayon-line">
  new Image().src = reportUrl + 'error=' + error;
</div>
<div id="crayon-5a707ba98744f433416112-4" class="crayon-line crayon-striped-line">
}
</div>
</div></td>
</tr>
</tbody>
</table>

实例 – 动态成立 img 标签进行汇报

*// 用火狐浏览器

特性监控

监控上报常见难题

下述例子我一切位居我的 github 上,读者可以自动查阅,前面不再赘言。

JavaScript

git clone cd blog/code/jserror/
npm install

1
2
3
git clone https://github.com/happylindz/blog.git
cd blog/code/jserror/
npm install

//文件名称获取形式  鼠标右键某一个文件 重命名  然后全选

最容易易行的性质监控

最广大的特性监控需要则是急需大家计算用户从伊始请求页面到具备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节点,可以参考下文有关首屏时间采集自动化的化解方案来对渲染时间举行贿赂。

Script error 脚本错误是什么

因为我们在线上的版本,常常做静态资源 CDN
化,那就会造成大家常访问的页面跟脚本文件来自分化的域名,那时候即使没有进展额外的配置,就会不难产生Script error。

澳门葡京 19

可通过 npm run nocors 查看效果。

Script error
是浏览器在同源策略限制下发生的,浏览器处于对安全性上的考虑,当页面引用非同域名外部脚本文件时中抛出非常的话,此时本页面是绝非义务知道那几个报错信息的,取而代之的是出口
Script error 那样的新闻。

澳门葡京 20

那样做的目的是幸免数据外泄到不安全的域中,举个大约的例证,

JavaScript

<script src=”xxxx.com/login.html”></script>

1
<script src="xxxx.com/login.html"></script>

地方大家并从未引入一个 js 文件,而是一个 html,这一个 html
是银行的记名页面,即使您早就报到了,那 login 页面就会自行跳转到
Welcome xxx...,若是未登录则跳转到 Please Login...,那么报错也会是
Welcome xxx... is not defined,Please Login... is not defined,通过那个信息能够看清一个用户是还是不是登录他的帐号,给侵略者提供了老大有益的判断渠道,那是万分不安全的。

介绍完背景后,那么我们应该去解决这些标题?

第一可以想到的方案肯定是同源化策略,将 JS 文件内联到 html
或者放置同域下,即便能简单可行地缓解 script error
难点,然则如此不可能运用好文件缓存和 CDN
的优势,不引进应用。正确的不二法门应该是从根本上缓解 script error 的错误。


performance

但是上述时间的监督过于简单,例如大家想统计文档的网络加载耗时、解析DOM的耗时与渲染DOM的耗时,就不太好办到了,所幸的是浏览器提供了window.performance接口,具体可知MDN文档

澳门葡京 21

差不多所有浏览器都帮忙window.performance接口,下边来看看在控制台打印window.performance可以获取些什么:

澳门葡京 22

可以看看,window,performance重点不外乎有memorynavigationtiming以及timeOriginonresourcetimingbufferfull方法。

  • navigation目标提供了在指定的时刻段里发出的操作相关信息,包蕴页面是加载照旧刷新、暴发了有些次重定向等等。
  • timing对象涵盖延迟相关的品质音信。那是大家页面加载质量优化需要中重点反映的相干新闻。
  • memoryChrome添加的一个非标准伸张,这些特性提供了一个方可拿走到基本内存使用状态的靶子。在其余浏览器应该考虑到这一个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>

跨源资源共享机制( CORS )

首先为页面上的 script 标签添加 crossOrigin 属性

JavaScript

// <script> window.onerror =
function (msg, url, row, col, error) {
console.log(‘我清楚不当了,也明白不当音信’); console.log({ msg, url,
row, col, error }) return true; }; </script> <script
src=”” crossorigin></script> //
setTimeout(() => { console.log(error);
})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// http://localhost:8080/index.html
<script>
  window.onerror = function (msg, url, row, col, error) {
    console.log(‘我知道错误了,也知道错误信息’);
    console.log({
      msg,  url,  row, col, error
    })
    return true;
  };
</script>
<script src="http://localhost:8081/test.js" crossorigin></script>
 
// http://localhost:8081/test.js
setTimeout(() => {
  console.log(error);
})

当你改改完前端代码后,你还需求非凡给后端在响应头里加上
Access-Control-Allow-Origin: localhost:8080,这里自己以 Koa 为例。

JavaScript

const Koa = require(‘koa’); const path = require(‘path’); const cors =
require(‘koa-cors’); const app = new Koa(); app.use(cors());
app.use(require(‘koa-static’)(path.resolve(__dirname, ‘./public’)));
app.listen(8081, () => { console.log(‘koa app listening at 8081’) });

1
2
3
4
5
6
7
8
9
10
11
const Koa = require(‘koa’);
const path = require(‘path’);
const cors = require(‘koa-cors’);
const app = new Koa();
 
app.use(cors());
app.use(require(‘koa-static’)(path.resolve(__dirname, ‘./public’)));
 
app.listen(8081, () => {
  console.log(‘koa app listening at 8081’)
});

澳门葡京 23

读者可经过 npm run cors
详细的跨域知识我就不举办了,有趣味可以看看我在此之前写的小说:跨域,你必要精晓的全在此处

您觉得这么就完了啊?并没有,下边就说有些 Script error 你不常遇见的点:

咱俩都精通 JSONP
是用来跨域获取数据的,并且包容性优秀,在一些用到中依旧会采纳到,所以你的系列中可能会用那样的代码:

JavaScript

// window.onerror = function (msg, url,
row, col, error) { console.log(‘我精通不当了,但不掌握不当音讯’);
console.log({ msg, url, row, col, error }) return true; }; function
jsonpCallback(data) { console.log(data); } const url =
”; const script =
document.createElement(‘script’); script.src = url;
document.body.appendChild(script);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// http://localhost:8080/index.html
window.onerror = function (msg, url, row, col, error) {
  console.log(‘我知道错误了,但不知道错误信息’);
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
function jsonpCallback(data) {
  console.log(data);
}
const url = ‘http://localhost:8081/data?callback=jsonpCallback’;
const script = document.createElement(‘script’);
script.src = url;
document.body.appendChild(script);

因为再次来到的消息会当做脚本文件来执行,一旦回到的剧本内容出错了,也是心有余而力不足捕捉到错误的信息。

澳门葡京 24

解决办法也简单,跟在此之前同一,在丰硕动态拉长脚本的时候添加
crossOrigin,并且在后端配上相应的 CORS 字段即可.

JavaScript

const script = document.createElement(‘script’); script.crossOrigin =
‘anonymous’; script.src = url; document.body.appendChild(script);

1
2
3
4
const script = document.createElement(‘script’);
script.crossOrigin = ‘anonymous’;
script.src = url;
document.body.appendChild(script);

读者可以通过 npm run jsonp 查看效果

澳门葡京 25

领会原理之后您或许会以为没关系,不就是给每个动态变化的本子添加
crossOrigin 字段嘛,不过在其实工程中,你或许是面向广大库来编程,比如动用
jQuery,Seajs 或者 webpack
来异步加载脚本,许多库封装了异步加载脚本的能力,以 jQeury
为例你也许是这么来触发异步脚本。

JavaScript

$.ajax({ url: ”, dataType: ‘jsonp’, success:
(data) => { console.log(data); } })

1
2
3
4
5
6
7
$.ajax({
  url: ‘http://localhost:8081/data’,
  dataType: ‘jsonp’,
  success: (data) => {
    console.log(data);
  }
})

只要那些库中从不提供 crossOrigin 的力量的话(jQuery jsonp
可能有,假装你不晓得),那您不得不去修改人家写的源代码了,所以自己那里提供一个思路,就是去要挟document.createElement,平素自上去为各类动态变化的剧本添加 crossOrigin
字段。

JavaScript

document.createElement = (function() { const fn =
document.createElement.bind(document); return function(type) { const
result = fn(type); if(type === ‘script’) { result.crossOrigin =
‘anonymous’; } return result; } })(); window.onerror = function (msg,
url, row, col, error) { console.log(‘我知道不当了,也领略不当音信’);
console.log({ msg, url, row, col, error }) return true; }; $.ajax({ url:
”, dataType: ‘jsonp’, success: (data) => {
console.log(data); } })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
document.createElement = (function() {
  const fn = document.createElement.bind(document);
  return function(type) {
    const result = fn(type);
    if(type === ‘script’) {
      result.crossOrigin = ‘anonymous’;
    }
    return result;
  }
})();
window.onerror = function (msg, url, row, col, error) {
  console.log(‘我知道错误了,也知道错误信息’);
  console.log({
    msg,  url,  row, col, error
  })
  return true;
};
$.ajax({
  url: ‘http://localhost:8081/data’,
  dataType: ‘jsonp’,
  success: (data) => {
    console.log(data);
  }
})

作用也是一模一样的,读者可以经过 npm run jsonpjq 来查看效果:

澳门葡京 26

如此那般重写 createElement
理论上没什么难题,不过侵略了本来的代码,不保险一定不会出错,在工程上或者需求多品尝下看看再利用,可能存在包容性上难题,假诺你觉得会油但是生什么样难点的话也欢迎留言商量下。

有关 Script error
的标题就写到这里,借使你通晓了下面的始末,基本上绝一大半的 Script error
都能缓解。

*// 1.除了文件夹之外的单个文件下载       文件名+后缀名   例: 
downOneFile(‘abc.mp3’)   单引号必须带着
//
downOneFile(‘某一个文本名称.后缀名’);

计量网站品质

使用performancetiming特性,可以得到页面品质相关的多寡,那里在广大篇章都有关系有关选用window.performance.timing记录页面品质的篇章,例如alloyteam集体写的初探
performance –
监控网页与程序品质,对于timing的各项品质含义,可以借助摘自此文的下图了解,以下代码摘自此文作为计量网站品质的工具函数参考:

澳门葡京 27

JavaScript

// 获取 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 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
响应全部收下达成的小时(获取到最后一个字节),包罗从地方读取缓存
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, // domContentLoaded伊夫ntStart: 1441112693093, //
domInteractive: 1441112693093, // domLoading: 1441112692690, //
domainLookupEnd: 1441112692155, // domainLookupStart: 1441112692155, //
fetchStart: 1441112692155, // load伊芙ntEnd: 1441112693215, //
load伊芙ntStart: 1441112693214, // navigationStart: 1441112691935, //
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 getPerformance提姆ing() { 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 即 提姆e 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;
}

window.onerror 能依旧不能捕获 iframe 的错误

当你的页面有应用 iframe 的时候,你须求对您引入的 iframe
做丰裕监控的拍卖,否则一经您引入的 iframe
页面出现了难点,你的主站突显不出来,而你却雾里看花。

首先须求强调,父窗口直接动用 window.onerror
是无力回天直接破获,假如你想要捕获 iframe 的百般的话,有分好两种意况。

设若你的 iframe 页面和你的主站是同域名的话,直接给 iframe 添加 onerror
事件即可。

JavaScript

<iframe src=”./iframe.html” frameborder=”0″></iframe>
<script> window.frames[0].onerror = function (msg, url, row,
col, error) { console.log(‘我晓得 iframe 的荒唐了,也亮堂不当新闻’);
console.log({ msg, url, row, col, error }) return true; };
</script>

1
2
3
4
5
6
7
8
9
10
<iframe src="./iframe.html" frameborder="0"></iframe>
<script>
  window.frames[0].onerror = function (msg, url, row, col, error) {
    console.log(‘我知道 iframe 的错误了,也知道错误信息’);
    console.log({
      msg,  url,  row, col, error
    })
    return true;
  };
</script>

读者可以透过 npm run iframe 查看效果:

澳门葡京 28

假如你置于的 iframe 页面和你的主站不是同个域名的,可是 iframe
内容不属于第三方,是你可以决定的,那么可以由此与 iframe
通讯的法子将极度音信抛给主站接收。与 iframe
通讯的办法有广大,常用的如:postMessage,hash 或者 name
字段跨域等等,那里就不开展了,感兴趣的话可以看:跨域,你必要知道的全在此间

假即使非同域且网站不受自己控制以来,除了通过控制台看到详细的错误信息外,无法捕获,那是由于安全性的设想,你引入了一个百度首页,人家页面报出的荒谬凭啥让你去监督呢,那会引出很多安全性的标题。

// 2.下载某一个文书夹   例:downOneFileBox(‘高校阿拉伯语四六级’)   
  
单引号必须带着
// 如若文件夹里面还有文件夹    就进入文件夹
调用  downFilelist()   进行列表打包下载    例: 
downOneFileBox(‘大学葡萄牙共和国(República Portuguesa)语六级课程’)
//
downOneFileBox(‘某一个文书夹名称’);

日志上报

削减代码怎样稳定到脚本非常地方

线上的代码大概都因此了滑坡处理,几十个文件打包成了一个并丑化代码,当我们吸收
a is not defined 的时候,大家平昔不清楚那些变量 a
究竟是怎么样含义,此时报错的失实日志显明是不行的。

率先想到的章程是行使 sourcemap
定位到错误代码的具体地方,详细内容可以参考:Sourcemap
定位脚本错误

除此以外也足以经过在卷入的时候,在各种合并的文本之间添加几行空格,并相应增进一些注明,那样在定位问题的时候很不难可以领悟是哪个文件报的不当,然后再经过有些器重词的摸索,可以便捷地稳住到难点的所在地方。

// 3.进去文件夹里面把所有文件打包下载       下载文件夹的话
最好利用那种方法
// 注:打包下载  是不分包文件夹的
// downFilelist();**

单独的日志域名

对于日记上报利用单独的日记域名的目标是幸免对工作造成影响。其一,对于服务器来说,大家必将不期待占用工作服务器的估算资源,也不愿意过多的日记在事情服务器堆积,造成工作服务器的仓储空间不够的意况。其二,我们清楚在页面开首化的经过中,会对页面加载时间、PV、UV等数据开展报告,那些报告请求会和加载业务数据大概是同时刻发生,而浏览器一般会对同一个域名的请求量有并发数的限量,如Chrome会有对并发数为6个的限定。由此须要对日记系统独立设定域名,最小化对页面加载质量造成的熏陶。

采集非凡消息量太多,怎么做

若是您的网站访问量很大,若是网页的 PV 有
1kw,那么一个毫无疑问的谬误发送的新闻就有 1kw
条,大家可以给网站设置一个采集率:

JavaScript

Reporter.send = function(data) { // 只采集 30% if(Math.random() <
0.3) { send(data) // 上报错误音信 } }

1
2
3
4
5
6
Reporter.send = function(data) {
  // 只采集 30%
  if(Math.random() < 0.3) {
    send(data)      // 上报错误信息
  }
}

以此采集率可以因而实际实际的情况来设定,方法多样化,可以使用一个肆意数,也足以切切实实依据用户的一点特征来拓展判断。

地点几乎是我对前者代码监控的部分了然,说起来不难,不过如果在工程化应用,难免须求考虑到包容性等样样难点,读者可以因而自己的具体意况举行调整,前端代码万分监控对于大家的网站的黑河久安起着紧要的意义。即便文中有所不对的地点,还望指正。

代码截止

跨域的标题

澳门葡京,对于单身的日记域名,肯定会波及到跨域的标题,选拔的缓解方案一般有以下二种:

  • 一种是构造空的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>

在自己的门类中接纳的是率先种的办法,也就是结构空的Image目的,不过我们通晓对于GET请求会有长度的限定,需求确保的是呼吁的尺寸不会超过阈值。

参考作品

  • 脚本错误量极致优化-监控上报与Script
    error
  • 前者代码极度日志收集与监控
  • 前者魔法堂——卓殊不仅仅是try/catch

    1 赞 2 收藏
    评论

 

节约响应中央

对于我们申报日志,其实对于客户端的话,并不需求考虑上报的结果,甚至对于报告败北,我们也不必要在前者做任何交互,所以报告来说,其实使用HEAD恳请就够了,接口重临空的结果,最大地回落上报日志造成的资源浪费。

用火狐浏览器

统一反映

恍如于7-Up图的合计,假使大家的应用要求报告的日志数量众多,那么有需求合并日志举办统一的反馈。

化解方案可以是尝试在用户距离页面或者零部件销毁时发送一个异步的POST恳请来拓展反馈,但是尝试在卸载(unload)文档从前向web服务器发送数据。保险在文档卸载时期发送数据一直是一个不方便。因为用户代理平常会忽视在卸载事件处理器中爆发的异步XMLHttpRequest,因为那时一度会跳转到下一个页面。所以那边是必须设置为一起的XMLHttpRequest请求吗?

JavaScript

window.add伊芙ntListener(‘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); }

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);
}

打开你要下载的视频页面 
等页面加载成功 **
然后**打开控制台 F12 控制台**

小结

用作前端开发者而言,要对产品保持敬畏之心,时刻保持对品质追求极致,对卓殊不可忍受的神态。前端的质量监控与更加申报显得尤其重大。

代码难免有标题,对于充裕可以行使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 收藏
评论

澳门葡京 29

复制代码初步到代码截至里面的有所内容 到控制台 
选拔3种下载形式中的一种即可 

去掉
downXXX() 后面的 ‘//’  直接回车 即可看到下载地址     不用的回想把前边的
‘//’ 加上

 

**假设认为下载慢的话  可以同盟 IDM 
接近满速下载**   

链接:
密码: 8mpv

 

一经遇上报错  试试以下两种方式:

1、清除缓存强制刷新页面

2、看看 console.log(111) 能或不能健康打印 
假如无法的话 就新建标签页 打开百度盘

3、关闭浏览器 清除缓存 打开浏览器
打开百度盘

即便上述措施都不能健康下载
可以给自家留言

重新强调 以上内容仅供沟通学习 

相关文章

发表评论

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

*
*
Website