前端报错监控和常见报错

参考资料:http://web.jobbole.com/93684/

了解源码,先贴地址有空来写

1.异常

1)常见错误类型
  1. RangeError,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值
  2. ReferenceError,当引用未声明的变量时发生
  3. SyntaxError,解析时发生语法错误
  4. TypeError,当值不是所期待的类型时,null.f()也报这个错
  5. URIError,当传递一个非法的URI给全局URI处理函数时发生,如decodeURIComponent('%'),即decodeURIComponentdecodeURI,encodeURIComponentencodeURI

举几个🌰,并没有按循序举🌰。(部分情况)

1.TypeError

TypeError

2.ReferenceError

3.URIError

4.SyntaxError(这里因为大写的符号)

5.RangeError

2)异常出现的特点

异常的出现不会直接导致 JS 引擎崩溃,最多只会使当前执行的任务终止。

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 lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

</body>
<script>
throw new Error('报错');
console.log('报错拉');
</script>
<script>
console.log('加载')
</script>

</html>
  1. 当前代码块将作为一个任务压入任务队列中,JS 线程会不断地从任务队列中提取任务执行。

  2. 当任务执行过程中出现异常,且异常没有捕获处理,则会一直沿着调用栈一层层向外抛出,最终终止当前任务的执行。

  3. JS 线程会继续从任务队列中提取下一个任务继续执行。

可以看到,第一个script标签下没有打印出来

2.三种监听报错的方式

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

1)try … catch…
即时运行错误一般使用try … catch…
1
2
3
4
5
6
7
8
try{
var name = "223";
console.log(Name);
}catch(err){
console.log(err);
}
// ReferenceError: Name is not defined
//还有一般序列化和反序列化的时候都需要使用try ... catch...。
try … catch…几种无法捕获的情况

​ 一般语法错误,就被编译器发现了

1
2
3
4
5
6
try {
var error = '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);
}
2)window.onerror = function(msg, url, line, col, error){}

​ 它有5个参数,分别是:

1
2
3
4
5
* @param {String} errorMessage  错误信息 
* @param {String} scriptURI 出错的文件
* @param {Long} lineNumber 出错代码的行号
* @param {Long} columnNumber 出错代码的列号
* @param {Object} errorObj 错误的详细信息,Anything

​ 它可以监听异步报错

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

</body>
<script>
window.onerror = function(msg, url, line, col, error){
console.log(msg);
console.log(url);
console.log(line);
console.log(col);
console.log(error);
}
</script>
<script>
setTimeout(function(){
error
},0)
</script>


</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
25
26
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<body>

</body>
<script>
error
</script>
<script>
window.onerror = function(msg, url, line, col, error){
console.log(msg);
console.log(url);
console.log(line);
console.log(col);
console.log(error);
}
</script>
</html>

可以看到

​ 图片404请求的时候

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<script>
window.onerror = function (msg, url, line, col, error) {
console.log(msg);
console.log(url);
console.log(line);
console.log(col);
console.log(error);
}
</script>

<body>
<img src="test.png" />
</body>

</html>

​ 可以看到

3)window.addEventListener(‘error’,function(err){})

效果与上面一个相同,不过上面那个比较好用。

3.错误上传

写个简单的🌰(省略了很多判断)

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<script>
function postError({ msg, url, line, col, error }) {
var xml = new XMLHttpRequest();
xml.onreadystatechange = function () {
if (xml.readyState == 4) {
if (xml.status == 200) {
console.log(xml.response);
}
}
}
xml.open('POST', 'http://localhost:8001/error', true);
xml.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xml.send(`msg=${msg}, url=${url}, line=${line}, col=${col}, error=${error} `);
}
</script>

<script>
window.onerror = function (msg, url, line, col, error) {
postError({ msg, url, line, col, error });
}
</script>
<script src="http://localhost:8001/error.js" type="text/javascript" crossOrigin></script>

<body>
</body>

</html>

Koa:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const Koa = require('koa');
const app = new Koa();

const path = require('path');
const cors = require('koa-cors');
const Router = require('koa-router');
const router = new Router();
const koaBody = require('koa-body');

router.post('/error', async (ctx, next) => {
const body = ctx.request.body;
console.log(body);
ctx.body = {
success: true
};
})
app.use(cors());
app.use(require('koa-static')(path.resolve(__dirname, './public')));
app.use(koaBody());
app.use(router.routes());
app.listen(8001, () => {
console.log('koa app listening at 8001')
});

可以看到请求

还可以看到后台打印出的结果

4.补充一下遇到过的问题

1)localStorage存满了的报错

公司app在登陆页的时候白屏,最后猜测可能是localStorage存满了,导致报错。

写个一直往缓存里存数据,致使报错的🌰。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>

</body>
<script>
window.onerror = function(msg,url,col,line,e){
console.log(msg,url,col,line,e);
}
</script>
<script>
setInterval(function(){ localStorage.setItem((new Date()).getTime(),'ssssssssssssssssssssssssssss') }, 0);//这个字符串要存很久才会看到报错。。
</script>
</html>

在浏览器上调试会抓到报错

然鹅我们的错误上传却没有这个错误。最后我尝试着使用window.addEventListener('error',function(err){})抓取这个报错,判断code为22,并且name为QuotaExceededError的时候,把缓存里必须的数据保存下来,删除其他无用的缓存。在浏览器调试正常,在真机调试的时候确抓不到这个报错。

2)script error

经常引入外部的脚本报错,确看不到具体的报错信息。

写个简单的🌰,页面error.html启在8000端口,后端使用koa,启在8001端口,error.html加载8001端口的脚本。关于跨域

error.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 lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<script>
window.onerror = function (msg, url, line, col, error) {
console.log(msg);
console.log(url);
console.log(line);
console.log(col);
console.log(error);
}
</script>
<script src="http://localhost:8001/error.js" type="text/javascript" ></script>
<body>
</body>

</html>

Index.js

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(8001, () => {
console.log('koa app listening at 8001')
});

error.js

1
2
var a = 2;
console.log(A);//大写的a

于是可以看到报错信息

script error: 是浏览器在同源策略限制下产生的,浏览器处于对安全性上的考虑,当页面引用非同域名外部脚本文件时中抛出异常的话,此时本页面是没有权利知道这个报错信息的,取而代之的是输出 script error这样的信息。

解决方案script标签内添加crossOrigin

error.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
25
26
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>

<script>
window.onerror = function (msg, url, line, col, error) {
console.log(msg);
console.log(url);
console.log(line);
console.log(col);
console.log(error);
}
</script>
<!--新增crossOrigin-->
<script src="http://localhost:8001/error.js" type="text/javascript" crossOrigin></script>

<body>
</body>

</html>

于是可以看到具体的报错信息