怎么捕获错误并且处理,是一门语言必备的知识。在JavaScript中也是如此。

那怎么捕获错误呢?初看好像很简单,try-catch就可以了嘛!但是有的时候我们发现情况却繁多复杂。

  • Q1: 同步可以try-catch,但一个异步回调,比如setTimeOut里的函数还可以try-catch吗?

  • Q2: Promise的错误捕获怎么做?

  • Q3: async/await怎么捕获错误?

  • Q4: 我能够在全局环境下捕获错误并且处理吗?

  • Q5: React16有什么新的错误捕获方式吗?

  • Q6: 捕获之后怎么上报和处理?

问题有点多,我们一个一个来。

Q1. 同步代码里的错误捕获方式

在同步代码里,我们是最简单的,只要try-catch就完了

  1. function test1 () {
  2. try {
  3. throw Error ('callback err');
  4. } catch (error) {
  5. console.log ('test1:catch err successfully');
  6. }
  7. }
  8. test1();

输出结果如下,显然是正常的

Q2. 普通的异步回调里的错误捕获方式(Promise时代以前)

上面的问题来了,我们还能通过直接的try-catch在异步回调外部捕获错误吗?我们试一试

  1. // 尝试在异步回调外部捕获错误的结果
  2. function test2 () {
  3. try {
  4. setTimeout (function () {
  5. throw Error ('callback err');
  6. });
  7. } catch (error) {
  8. console.log ('test2:catch err successfully');
  9. }
  10. }
  11. test2(); 

输出

注意这里的Uncaught Error的文本,它告诉我们错误没有被成功捕捉。

为什么呢? 因为try-catch的是属于同步代码,它执行的时候,setTimeOut内部的的匿名函数还没有执行呢。而内部的那个匿名函数执行的时候,try-catch早就执行完了。( error的内心想法:哈哈,只要我跑的够慢,try-catch还是追不上我!)

但是我们简单想一想,诶我们把try-catch写到函数里面不就完事了嘛!

  1. function test2_1 () {
  2. setTimeout (function () {
  3. try {
  4. throw Error ('callback err');
  5. } catch (error) {
  6. console.log ('test2_1:catch err successfully');
  7. }
  8. });
  9. }
  10. test2_1();

输出结果如下,告诉我们这方法可行

总结下Promise时代以前,异步回调中捕获和处理错误的方法

  • 在异步回调内部编写try-catch去捕获和处理,不要在外部哦

  • 很多异步操作会开放error事件,我们根据事件去操作就可以了

Q3. Promise里的错误捕获方式

可通过Promise.catch方法捕获

  1. function test3 () {
  2. new Promise ((resolve, reject) => {
  3. throw Error ('promise error');
  4. }).catch (err => {
  5. console.log ('promise error');
  6. });
  7. }

输出结果

>> reject方法调用和throw Error都可以通过Promise.catch方法捕获

  1. function test4 () {
  2. new Promise ((resolve, reject) => {
  3. reject ('promise reject error');
  4. }).catch (err => {
  5. console.log (err);
  6. });
  7. } 

输出结果

>> then方法中的失败回调和Promise.catch的关系

  • 如果前面的then方法没写失败回调,失败时后面的catch是会被调用的

  • 如果前面的then方法写了失败回调,又没抛出,那么后面的catch就不会被调用了

  1. // then方法没写失败回调
  2. function test5 () {
  3. new Promise ((resolve, reject) => {
  4. throw Error ('promise error');
  5. })
  6. .then (success => {})
  7. .catch (err => {
  8. console.log ('the error has not been swallowed up');
  9. });
  10. }
  11. // then方法写了失败回调
  12. function test5 () {
  13. new Promise ((resolve, reject) => {
  14. throw Error ('promise error');
  15. })
  16. .then (success => {},err => {})
  17. .catch (err => {
  18. console.log ('the error has not been swallowed up');
  19. });
  20. }

输出分别为

  1. 1.the error has not been swallowed up
  1. 2.无输出

Q4.async/await里的错误捕获方式

对于async/await这种类型的异步,我们可以通过try-catch去解决

  1. async function test6 () {
  2. try {
  3. await getErrorP ();
  4. } catch (error) {
  5. console.log ('async/await error with throw error');
  6. }
  7. }
  8.  
  9. function getErrorP () {
  10. return new Promise ((resolve, reject) => {
  11. throw Error ('promise error');
  12. });
  13. }
  14. test6();
  1.  

输出结果如下

>> 如果被await修饰的Promise因为reject调用而变化,它也是能被try-catch的

(我已经证明了这一点,但是这里位置不够,我写不下了)

Q5.在全局环境下如何监听错误

window.onerror可以监听全局错误,但是很显然错误还是会抛出

  1. window.onerror = function (err) {
  2. console.log ('global error');
  3. };
  4. throw Error ('global error');

输出如下

Q6.在React16以上如何监听错误

>> componentDidCatch和getDerivedStateFromError钩子函数

  1. class Bar extends React.Component {
  2. // 监听组件错误
  3. componentDidCatch(error, info) {
  4. this.setState({ error, info });
  5. }
  6. // 更新 state 使下一次渲染能够显示降级后的 UI
  7. static getDerivedStateFromError(error) {
  8. return { hasError: true };
  9. }
  10. render() {
  11. }
  12. }

有错误,那肯定要上报啊!不上报就发现不了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的支持也可以说是面面俱到

  1. 参考链接
  2. https://docs.sentry.io/platforms/ 

Sentry的功能简单说就是,你在代码中catch错误,然后调用Sentry的方法,然后Sentry就会自动帮你分析和整理错误日志,例如下面这张图截取自Sentry的网站中

在JavaScript中使用Sentry

1.首先呢,你当然要注册Sentry的账号

这个时候Sentry会自动给你分配一个唯一标示,这个标示在Sentry里叫做 dsn

2. 安卓模块并使用基础功能

安装@sentry/browser

  1. npm install @sentry/browser

在项目中初始化并使用

  1. import * as Sentry from '@sentry/browser';
  2.  
  3. Sentry.init ({
  4. dsn: 'xxxx',
  5. });
  6.  
  7. try {
  8. throw Error ('我是一个error');
  9. } catch (err) {
  10. // 捕捉错误
  11. Sentry.captureException (err);
  12. }

3.上传sourceMap以方便在线上平台阅读出错的源码

  1. // 安装
  2. $ npm install --save-dev @sentry/webpack-plugin
  3. $ yarn add --dev @sentry/webpack-plugin
  4.  
  5. // 配置webpack
  6. const SentryWebpackPlugin = require('@sentry/webpack-plugin');
  7. module.exports = {
  8. // other configuration
  9. plugins: [
  10. new SentryWebpackPlugin({
  11. include: '.',
  12. ignoreFile: '.sentrycliignore',
  13. ignore: ['node_modules', 'webpack.config.js'],
  14. configFile: 'sentry.properties'
  15. })
  16. ]
  17. }; 

4. 为什么不是raven.js?

  1. // 已经废弃,虽然你还是可以用
  2. var Raven = require('raven-js');
  3. Raven
  4. .config('xxxxxxxxxxx_dsn')
  5. .install();

Sentry的核心功能总结

捕获错误

  1. try {
  2. aFunctionThatMightFail();
  3. } catch (err) {
  4. Sentry.captureException(err);
  5. }

设置该错误发生的用户信息

下面每个选项都是可选的,但必须 存在一个选项 才能使Sentry SDK捕获用户: id

  1. Sentry.setUser({
  2. id:"penghuwan12314"
  3. email: "penghuwan@example.com",
  4. username:"penghuwan",
  5. ip_addressZ:'xxx.xxx.xxx.xxx'
  6. });

设置额外数据

  1. Sentry.setExtra("character_name", "Mighty Fighter");
  1. 设置作用域 
  1. Sentry.withScope(function(scope) {
  2. // 下面的set的效果只存在于函数的作用域内
  3. scope.setFingerprint(['Database Connection Error']);
  4. scope.setUser(someUser);
  5. Sentry.captureException(err);
  6. });
  7. // 在这里,上面的setUser的设置效果会消失

设置错误的分组

整理日志信息,避免过度冗余

  1. Sentry.configureScope(function(scope) {
  2. scope.setFingerprint(['my-view-function']);
  3. });

设置错误的级别

在阅读日志时可以确定各个bug的紧急度,确定排查的优先书序

  1. Sentry.captureMessage('this is a debug message', 'debug');
  2. //fatal,error,warning,info,debug五个值
  3. // fatal最严重,debug最轻

自动记录某些事件

例如下面的方法,会在每次屏幕调整时完成上报

  1. window.addEventListener('resize', function(event){
  2. Sentry.addBreadcrumb({
  3. category: 'ui',
  4. message: 'New window size:' + window.innerWidth + 'x' + window.innerHeight,
  5. level: 'info'
  6. });
  7. })

Sentry实践的运用

根据环境设置不同的dsn

  1. let dsn;
  2. if (env === 'test') {
  3. dsn = '测试环境的dsn';
  4. } else {
  5. dsn =
  6. '正式环境的dsn';
  7. }
  8.  
  9. Sentry.init ({
  10. dsn
  11. });
  1.  

详解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. 绕过CDN方法整理

    来自文章链接:https://zhuanlan.zhihu.com/p/33440472 0x01 判断ip是否为网站真实ip 1. Nslookup: Win下使用nslookup命令进行查询,若返 ...

  2. PHP代码审计辅助脚本

    #!/usr/bin/env python import sys import os def main(): print ''' -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ...

  3. [USACO10NOV]奶牛的图片Cow Photographs

    题目描述 Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片,这样他就可以向他的朋友炫耀他的奶牛. 这N只奶牛被标号为1..N. 在照相的那一天,奶牛们排成了一排 ...

  4. Ubuntu 16.04 集成安装Apache+PHP+Kerberos+LDAP+phpLDAPadmin

    一.安装Apache 1.1.安装Apache apt-get update apt-get install apache2 过程如下: root@duke01:~# apt-get update命中 ...

  5. ndnsim结果分析

    ndnSIM中提供了几种trace用来对仿真结果进行跟踪,生成数据文件txt 官网地址: https://ndnsim.net/current/metric.html#packet-trace-hel ...

  6. Java类型信息(RTTI和反射)

    要想在IT领域站得住脚,必须得不断地学习来强化自己,但是学过的技术不实践很容易便被遗忘,所以一直都打算开个博客,来记录自己学的知识,另外也可以分享给有需要的人! 最近在学习反射,为了更好地理解反射,就 ...

  7. 树莓派apt报错:E: '\Release' 这个值对 APT::Default-Release 是无效的,因为在源里找不到这样的发行

    E: '\jessie' 这个值对 APT::Default-Release 是无效的,因为在源里找不到这样的发行 开始尝试了各种方法, 换apt源, 改/etc/apt/apt.conf.d/10d ...

  8. IOT设备的7大安全问题

    IOT设备的7大安全问题 串口安全 IOT设备一般包含各类串口,并且这些串口缺乏认证机制.一旦暴露给了hacker,hacker可以很容易的查找敏感信息和dump固件,从而导致各类安全问题.建议厂家在 ...

  9. CCBPM工作流系统中如何在特定的一个步骤,调用起另外一条流程

    关键词: 工作流快速开发平台  工作流设计  业务流程管理   asp.net 开源工作流bpm工作流系统  java工作流主流框架  自定义工作流引擎 需求描述: 1, 操作员在操作最后一个节点时, ...

  10. 暑期集训20190729 字典序(dictionary)

    [题目描述] 你需要构造一个1~n的排列,使得它满足m个条件,每个条件形如(ai,bi),表示ai必须在bi前面. 在此基础上,你需要让1尽可能靠前,然后你需要让2尽可能靠前,然后是3,4,5,…,n ...