怎么捕获错误并且处理,是一门语言必备的知识。在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错误捕获和上报流程的更多相关文章

  1. 【转】详解JavaScript中的this

    ref:http://blog.jobbole.com/39305/ 来源:foocoder 详解JavaScript中的this JavaScript中的this总是让人迷惑,应该是js众所周知的坑 ...

  2. 详解JavaScript调用栈、尾递归和手动优化

    调用栈(Call Stack) 调用栈(Call Stack)是一个基本的计算机概念,这里引入一个概念:栈帧. 栈帧是指为一个函数调用单独分配的那部分栈空间. 当运行的程序从当前函数调用另外一个函数时 ...

  3. 详解JavaScript的任务、微任务、队列以及代码执行顺序

    摘要: 理解JS的执行顺序. 作者:前端小智 原文:详解JavaScript的任务.微任务.队列以及代码执行顺序 思考下面 JavaScript 代码: console.log("scrip ...

  4. 详解javascript的类

    前言 生活有度,人生添寿. 原文地址:详解javascript的类 博主博客地址:Damonare的个人博客 Javascript从当初的一个"弹窗语言",一步步发展成为现在前后端 ...

  5. 详解Javascript的继承实现(二)

    上文<详解Javascript的继承实现>介绍了一个通用的继承库,基于该库,可以快速构建带继承关系和静态成员的javascript类,好使用也好理解,额外的好处是,如果所有类都用这种库来构 ...

  6. js对象详解(JavaScript对象深度剖析,深度理解js对象)

    js对象详解(JavaScript对象深度剖析,深度理解js对象) 这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕 ...

  7. 第三节:带你详解Java的操作符,控制流程以及数组

    前言 大家好,给大家带来带你详解Java的操作符,控制流程以及数组的概述,希望你们喜欢 操作符 算数操作符 一般的 +,-,*,/,还有两个自增 自减 ,以及一个取模 % 操作符. 这里的操作算法,一 ...

  8. 详解 javascript中offsetleft属性的用法(转)

    详解 javascript中offsetleft属性的用法 转载  2015-11-11   投稿:mrr    我要评论 本章节通过代码实例介绍一下offsetleft属性的用法,需要的朋友可以做一 ...

  9. 详解javascript中的this对象

    详解javascript中的this对象 前言 Javascript是一门基于对象的动态语言,也就是说,所有东西都是对象,一个很典型的例子就是函数也被视为普通的对象.Javascript可以通过一定的 ...

随机推荐

  1. [网络流 24 题] luoguP2763 试题库问题

    [返回网络流 24 题索引] 题目描述 假设一个试题库中有 nnn 道试题.每道试题都标明了所属类别.同一道题可能有多个类别属性.现要从题库中抽取 mmm 道题组成试卷.并要求试卷包含指定类型的试题. ...

  2. MVC路径无匹配或请求api版本过低时处理

    解决方案:RequestMappingHandlerMapping中重写handleNoMatch方法,springMVC和springboot中配置无区别. 另: 1.可搭配advice处理抛出的异 ...

  3. 为程序员节日献礼--2019中国.NET开发者峰会主题内容发布

    2019年10月24日,组委会正式发布了China .NET Conf 2019中国 .NET 开发者峰会的主题内容. 2014年微软组织并成立.NET基金会,微软在成为主要的开源参与者的道路上又前进 ...

  4. Linux的一些常用命令(一)

    linux 快捷键1.ls 列出本地址上文件, -a 列出所有(包括隐藏文件) -l 按照列表方式显示 -t 按照时间方式排序 2.touch 创建文件 3.  echo 'abc' > 文件名 ...

  5. opencv实践::透视变换

    问题描述 拍摄或者扫描图像不是规则的矩形,会对后期处理产生不 好影响,需要通过透视变换校正得到正确形状. 解决思路 通过二值分割 + 形态学方法 + Hough直线 +透视变换 #include &l ...

  6. 《Java并发编程实战》读书笔记-第3章 对象的共享

    可见性 在没有同步的情况下,编译器.处理器以及运行时都可能做指令重排.执行结果可能会出现错误 volatile变量 编译器与运行时不会进行指令重排,不会进行缓存,使用volatile变量要满足以下条件 ...

  7. xml 文件操作

      'XML添加   Public Sub Add(ID As String, RFSerialnumber As String, Mood As Integer)     If reatch(RFS ...

  8. 整洁的 Table View 代码

    Table view 是 iOS 应用程序中非常通用的组件.许多代码和 table view 都有直接或间接的关系,随便举几个例子,比如提供数据.更新 table view,控制它的行为以及响应选择事 ...

  9. 音视频入门-11-PNG文件格式详解

    * 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...

  10. 百万年薪python之路 -- MySQL数据库之 用户权限

    MySQL用户授权 (来自于https://www.cnblogs.com/dong-/p/9667787.html) 一. 对新用户的增删改 1. 增加用户 : ①. 指定某一个用户使用某一个ip登 ...