详解JavaScript错误捕获和上报流程

怎么捕获错误并且处理,是一门语言必备的知识。在JavaScript中也是如此。
那怎么捕获错误呢?初看好像很简单,try-catch就可以了嘛!但是有的时候我们发现情况却繁多复杂。
Q1: 同步可以try-catch,但一个异步回调,比如setTimeOut里的函数还可以try-catch吗?
Q2: Promise的错误捕获怎么做?
Q3: async/await怎么捕获错误?
Q4: 我能够在全局环境下捕获错误并且处理吗?
Q5: React16有什么新的错误捕获方式吗?
Q6: 捕获之后怎么上报和处理?
问题有点多,我们一个一个来。
Q1. 同步代码里的错误捕获方式
在同步代码里,我们是最简单的,只要try-catch就完了
function test1 () {
try {
throw Error ('callback err');
} catch (error) {
console.log ('test1:catch err successfully');
}
}
test1();
输出结果如下,显然是正常的
Q2. 普通的异步回调里的错误捕获方式(Promise时代以前)
上面的问题来了,我们还能通过直接的try-catch在异步回调外部捕获错误吗?我们试一试
// 尝试在异步回调外部捕获错误的结果
function test2 () {
try {
setTimeout (function () {
throw Error ('callback err');
});
} catch (error) {
console.log ('test2:catch err successfully');
}
}
test2();
输出
注意这里的Uncaught Error的文本,它告诉我们错误没有被成功捕捉。
为什么呢? 因为try-catch的是属于同步代码,它执行的时候,setTimeOut内部的的匿名函数还没有执行呢。而内部的那个匿名函数执行的时候,try-catch早就执行完了。( error的内心想法:哈哈,只要我跑的够慢,try-catch还是追不上我!)
但是我们简单想一想,诶我们把try-catch写到函数里面不就完事了嘛!
function test2_1 () {
setTimeout (function () {
try {
throw Error ('callback err');
} catch (error) {
console.log ('test2_1:catch err successfully');
}
});
}
test2_1();
输出结果如下,告诉我们这方法可行
总结下Promise时代以前,异步回调中捕获和处理错误的方法
在异步回调内部编写try-catch去捕获和处理,不要在外部哦
很多异步操作会开放error事件,我们根据事件去操作就可以了
Q3. Promise里的错误捕获方式
可通过Promise.catch方法捕获
function test3 () {
new Promise ((resolve, reject) => {
throw Error ('promise error');
}).catch (err => {
console.log ('promise error');
});
}
输出结果
>> reject方法调用和throw Error都可以通过Promise.catch方法捕获
function test4 () {
new Promise ((resolve, reject) => {
reject ('promise reject error');
}).catch (err => {
console.log (err);
});
}
输出结果
>> then方法中的失败回调和Promise.catch的关系
如果前面的then方法没写失败回调,失败时后面的catch是会被调用的
如果前面的then方法写了失败回调,又没抛出,那么后面的catch就不会被调用了
// then方法没写失败回调
function test5 () {
new Promise ((resolve, reject) => {
throw Error ('promise error');
})
.then (success => {})
.catch (err => {
console.log ('the error has not been swallowed up');
});
}
// then方法写了失败回调
function test5 () {
new Promise ((resolve, reject) => {
throw Error ('promise error');
})
.then (success => {},err => {})
.catch (err => {
console.log ('the error has not been swallowed up');
});
}
输出分别为
1.the error has not been swallowed up
2.无输出
Q4.async/await里的错误捕获方式
对于async/await这种类型的异步,我们可以通过try-catch去解决
async function test6 () {
try {
await getErrorP ();
} catch (error) {
console.log ('async/await error with throw error');
}
}
function getErrorP () {
return new Promise ((resolve, reject) => {
throw Error ('promise error');
});
}
test6();
输出结果如下
>> 如果被await修饰的Promise因为reject调用而变化,它也是能被try-catch的
(我已经证明了这一点,但是这里位置不够,我写不下了)
Q5.在全局环境下如何监听错误
window.onerror可以监听全局错误,但是很显然错误还是会抛出
window.onerror = function (err) {
console.log ('global error');
};
throw Error ('global error');
输出如下
Q6.在React16以上如何监听错误
>> componentDidCatch和getDerivedStateFromError钩子函数
class Bar extends React.Component {
// 监听组件错误
componentDidCatch(error, info) {
this.setState({ error, info });
}
// 更新 state 使下一次渲染能够显示降级后的 UI
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
}
}
有错误,那肯定要上报啊!不上报就发现不了Bug这个样子。Sentry这位老哥就是个人才,日志记录又好看,每次见面就像回家一样
Sentry简单介绍
Sentry provides open-source and hosted error monitoring that helps all software
teams discover, triage, and prioritize errors in real-time.
One million developers at over fifty thousand companies already ship
better software faster with Sentry. Won’t you join them?
—— Sentry官网
Sentry是一个日志上报系统,Sentry 是一个实时的日志记录和汇总处理的平台。专注于错误监控,发现和数据处理,可以让我们不再依赖于用户反馈才能发现和解决线上bug。让我们简单看一下Sentry支持哪些语言和平台吧
在JavaScript领域,Sentry的支持也可以说是面面俱到
参考链接
https://docs.sentry.io/platforms/
Sentry的功能简单说就是,你在代码中catch错误,然后调用Sentry的方法,然后Sentry就会自动帮你分析和整理错误日志,例如下面这张图截取自Sentry的网站中
在JavaScript中使用Sentry
1.首先呢,你当然要注册Sentry的账号
这个时候Sentry会自动给你分配一个唯一标示,这个标示在Sentry里叫做 dsn
2. 安卓模块并使用基础功能
安装@sentry/browser
npm install @sentry/browser
在项目中初始化并使用
import * as Sentry from '@sentry/browser';
Sentry.init ({
dsn: 'xxxx',
});
try {
throw Error ('我是一个error');
} catch (err) {
// 捕捉错误
Sentry.captureException (err);
}
3.上传sourceMap以方便在线上平台阅读出错的源码
// 安装
$ npm install --save-dev @sentry/webpack-plugin
$ yarn add --dev @sentry/webpack-plugin // 配置webpack
const SentryWebpackPlugin = require('@sentry/webpack-plugin');
module.exports = {
// other configuration
plugins: [
new SentryWebpackPlugin({
include: '.',
ignoreFile: '.sentrycliignore',
ignore: ['node_modules', 'webpack.config.js'],
configFile: 'sentry.properties'
})
]
};
4. 为什么不是raven.js?
// 已经废弃,虽然你还是可以用
var Raven = require('raven-js');
Raven
.config('xxxxxxxxxxx_dsn')
.install();
Sentry的核心功能总结
捕获错误
try {
aFunctionThatMightFail();
} catch (err) {
Sentry.captureException(err);
}
设置该错误发生的用户信息
下面每个选项都是可选的,但必须 存在一个选项 才能使Sentry SDK捕获用户: id
Sentry.setUser({
id:"penghuwan12314"
email: "penghuwan@example.com",
username:"penghuwan",
ip_addressZ:'xxx.xxx.xxx.xxx'
});
设置额外数据
Sentry.setExtra("character_name", "Mighty Fighter");
设置作用域
Sentry.withScope(function(scope) {
// 下面的set的效果只存在于函数的作用域内
scope.setFingerprint(['Database Connection Error']);
scope.setUser(someUser);
Sentry.captureException(err);
});
// 在这里,上面的setUser的设置效果会消失
设置错误的分组
整理日志信息,避免过度冗余
Sentry.configureScope(function(scope) {
scope.setFingerprint(['my-view-function']);
});
设置错误的级别
在阅读日志时可以确定各个bug的紧急度,确定排查的优先书序
Sentry.captureMessage('this is a debug message', 'debug');
//fatal,error,warning,info,debug五个值
// fatal最严重,debug最轻
自动记录某些事件
例如下面的方法,会在每次屏幕调整时完成上报
window.addEventListener('resize', function(event){
Sentry.addBreadcrumb({
category: 'ui',
message: 'New window size:' + window.innerWidth + 'x' + window.innerHeight,
level: 'info'
});
})
Sentry实践的运用
根据环境设置不同的dsn
let dsn;
if (env === 'test') {
dsn = '测试环境的dsn';
} else {
dsn =
'正式环境的dsn';
} Sentry.init ({
dsn
});
详解JavaScript错误捕获和上报流程的更多相关文章
- 【转】详解JavaScript中的this
ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...
- 详解JavaScript调用栈、尾递归和手动优化
调用栈(Call Stack) 调用栈(Call Stack)是一个基本的计算机概念,这里引入一个概念:栈帧. 栈帧是指为一个函数调用单独分配的那部分栈空间. 当运行的程序从当前函数调用另外一个函数时 ...
- 详解JavaScript的任务、微任务、队列以及代码执行顺序
摘要: 理解JS的执行顺序. 作者:前端小智 原文:详解JavaScript的任务.微任务.队列以及代码执行顺序 思考下面 JavaScript 代码: console.log("scrip ...
- 详解javascript的类
前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...
- 详解Javascript的继承实现(二)
上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...
- js对象详解(JavaScript对象深度剖析,深度理解js对象)
js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...
- 第三节:带你详解Java的操作符,控制流程以及数组
前言 大家好,给大家带来带你详解Java的操作符,控制流程以及数组的概述,希望你们喜欢 操作符 算数操作符 一般的 +,-,*,/,还有两个自增 自减 ,以及一个取模 % 操作符. 这里的操作算法,一 ...
- 详解 javascript中offsetleft属性的用法(转)
详解 javascript中offsetleft属性的用法 转载 2015-11-11 投稿:mrr 我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...
- 详解javascript中的this对象
详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...
随机推荐
- vue-cli 3.x 自定义插件并发布到 npm
干货转载——https://www.cnblogs.com/wisewrong/archive/2018/12/28/10186611.html 全是知识点呐 赶紧记下来啊 一.调整项目结构 首先用 ...
- insert into select 引起的 "子查询返回的值不止一个。当子查询跟随在**之后,或子查询用作表达式时,这种情况是不允许的"
目录 1.事故现场 1.1 在使用 Insert into Table2 select * from Table1 将表1的数据插入到表2时,报错如下: 1.2 sql 语句 2.推测 3.解决方案 ...
- 16.Linux yum扩展
1.列出yum源可用的软件仓库 [root@yinwucheng ~]# yum repolist [root@yinwucheng ~]# yum repolist all 查看所有的仓库 ``` ...
- Etcd安装和使用
Etcd安装和使用 一.安装 1.1 二进制安装 从这里下载: etcd-v3.2.11-linux-amd64.tar.gz 下载包后解压即可运行: # 解压 tar zxvf etcd-v3.2. ...
- Spring事务传播属性有那么难理解吗?
学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过几天就会忘记,接下来我们一起实践来学习Spring事务的传播属性. 传播属性 传播属性定义的是当一个事务方法碰到另一个事 ...
- 雷子聊并发编程(001):基础知识之串行&并行&并发
前言 编写正确的程序很难,而编写正确的并发程序则难上加难.与串行程序相比,在并发程序中存在更多容易出错的地方.那么,为什么还要编写并发程序?原因很简单,能充分发挥与利用多处理器系统的强大计算能力. 在 ...
- 如何在chrome使用vue-devtool?
1.在应用中安装 2.去查找文件 C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Extensions\nhd ...
- R语言:绘制知识图谱
知识图谱主要是通过将应用数学,图形学,信息可视化技术,信息科学等学科的理论与方法与计量学引文分析.共现分析等方法结合,利用可视化的图谱形象地展示学科的核心结构.发展历史.前沿领域以及整体知识架构达到多 ...
- JVM内存结构、参数调优和内存泄露分析
1. JVM内存区域和参数配置 1.1 JVM内存结构 Java堆(Heap) Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建.此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都 ...
- Android H5混合开发(2):自定义Cordova插件
前言 Cordova虽然定义了很多基础的插件,供H5端使用原生设备的功能. 但是,如果业务相关的功能,需要提供给H5端使用,那么,就需要我们自定义插件了. 这个"自定义"不是指由A ...