Comments (9)
reject 如果使用 Error 对象,会导致捕获不到错误的情况
@ascoders reject 使用 Error 对象指的是 reject(new Error('your message here')
,并不是 throw
。这样写比使用字符串优点是做统一错误处理时更加容易。使用 Promise 时要注意避免 try...catch
和 throw
的陷阱。
from weekly.
对 @camsong 的观点补充一下,reject
如果使用 Error
对象,会导致捕获不到错误的情况,在我的博客中有讨论过这种情况:Callback Promise Generator Async-Await 和异常处理的演进。
我们看以下代码:
function thirdFunction() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('我可以被捕获')
// throw Error('永远无法被捕获')
})
})
}
Promise.resolve(true).then((resolve, reject) => {
return thirdFunction()
}).catch(error => {
console.log('捕获异常', error) // 捕获异常 我可以被捕获
})
我们发现,在 macrotask
队列中,reject
行为是可以被 catch
到的,而此时 throw Error
就无法捕获异常,大家可以贴到浏览器运行试一试,第二次把 reject(666)
注释起来,取消 throw Error(666)
的注释,会发现异常无法 catch
住。
这是因为 setTimeout
中 throw Error
无论如何都无法捕获到,而 reject
是 Promise
提供的关键字,自己当然可以 catch
住。
from weekly.
中文版译文地址:https://zhuanlan.zhihu.com/p/25338849
from weekly.
这篇文章核心介绍了 captureStackTrace
方法的使用,通过截取有意义报错堆栈,并统计上报,有助于排查问题。
常用的断言库 chai
就是通过此方式屏蔽了库自身的调用栈,仅保留了用户代码的调用栈,这样用户会清晰的看到自己代码的调用栈。
关于 V8性能优化 里提到,只要 try..catch
分离到单独函数中,引擎就可以优化代码,所以不用顾虑性能问题了。
from weekly.
Chai.js 的核心维护者通过介绍 Error.captureStackTrace
方法给我们揭露了 chai 实现优雅调用栈的黑科技。实际上,现在有另外一款更黑科技的断言库正在崛起,那就是 power-assert.
直观的看一下 Chai.js 和 power-assert 的用法及反馈效果(以下代码及截图来自小菜荔枝):
const assert = require('power-assert');
const should = require('should'); // 别忘记 npm install should
const obj = {
arr: [1,2,3],
number: 10
};
describe('should.js和power-assert的区别', () => {
it('使用should.js的情况', () => {
should(obj.arr[0]).be.equal(obj.number); // should api
});
it('使用power-assert的情况', () => {
assert(obj.arr[0] === obj.number); // 用assert就可以
});
});
不难看出,power-assert 不仅能给出清晰的调用栈,更能告诉你具体断言的每个变量值是什么。
from weekly.
这篇文章里提出了一些异常处理的技巧,重要的一点是 throw 时要使用 Error 对象。不要抛出非 Error 对象的值,如数字或字符串。因为这样无法知道抛出的类型就很难对错误进行统一处理。正确的做法应该是使用 throw new Error(“error message here”)
。另外作者建议 Promise 的 reject
时也使用 Error 对象而不是字符串。
异常处理还有很多点需要考虑,这里有 Node.js 使用的异常处理方式 https://www.joyent.com/node-js/production/design/errors ,列出我感觉好的几点:
- 区分操作异常和程序员的失误。操作异常指可预测的不可避免的异常,如无法连接服务器
- 操作异常应该被处理。程序员的失误不需要处理,如果处理了反而会影响错误排查
- 操作异常有两种处理方式:同步 (try…catch) 和异步(callback, event emitter)两种处理方式,但只能选择其中一种。
- 函数定义时应该用文档写清楚参数类型,及可能会发生的合理的失败。以及错误是同步还是异步传给调用者的
- 缺少参数或参数无效是程序员的错误,一旦发生就应该
throw
。 - 传递错误时,使用标准的
Error
对象,并附件尽可能多的错误信息,可以使用标准的属性名
from weekly.
文章开篇部分就讲解了 Stack Trace 和 Error 的基础。
Stack 部分主要在阐明 js 中函数调用栈的概念,它符合栈的基本特性『当调用时,压入栈顶。当它执行完毕时,被弹出栈』,简单看下面的代码:
function c() {
try {
var bar = baz;
throw new Error()
} catch (e) {
console.log(e.stack);
}
}
function b() {
c();
}
function a() {
b();
}
a();
上述代码中会在执行到 c 函数的时候跑错,调用栈为 a -> b -> c
,如下图所示:
很明显,错误堆栈可以帮助我们定位到报错的位置,在大型项目或者类库开发时,这很有意义。
紧接着,原作者讲到了 Error 对象,主要有两个重要属性 message 和 name 分别表示错误信息和错误名称。实际上,除了这两个属性还有一个未被标准化的 stack 属性,我们上面的代码也用到了 e.stack
,这个属性包含了错误信息、错误名称以及错误栈信息。在 chrome 中测试打印出 e.stack
于 e
类似。感兴趣的可以了解下 Sentry 的 stack traces,他集成了 TraceKit,会对 Error 对象进行规范化处理。
接下来当然就是捕获错误,这里作者也提到了 try...catch
,它可以拿到出错的信息,堆栈,出错的文件、行号、列号等,但无法捕捉到语法错误,也没法去捕捉全局的异常事件。当然,也有一些异常监控的工具会把所有的 function 和文件块中加入 try...catch
来捕捉更多的静态信息。此外,在一些古老的浏览器下
try...catch
对 js 的性能也有一定的影响,而且对异步操作中的异常支持不好。
这里,想提一下另一个捕捉异常的方法,即 window.onerror
,这也是我们在做错误监控中用到比较多的方案。它可以捕捉语法错误和运行时错误,并且拿到出错的信息,堆栈,出错的文件、行号、列号等。不过,由于是全局监测,就会统计到浏览器插件中的 js 异常。当然,还有一个问题就是浏览器跨域,页面和 js 代码在不同域上时,浏览器出于安全性的考虑,将异常内容隐藏,我们只能获取到一个简单的 Script Error
信息。不过这个解决方案也很成熟:
- 给应用内所需的 <script> 标签添加 crossorigin 属性;
- 在 js 所在的 cdn 服务器上添加
Access-Control-Allow-Origin: *
HTTP 头;
from weekly.
对,补充一点,我也很反对 chai
的断言方式,过分语义化反而让代码更难读,有一种在使用 易语言
的感觉:
should(obj.arr[0]).be.equal(obj.number)
所以,我支持 avajs 的方式:
test.true(1 === count)
test.is(str, 'ok')
from weekly.
专栏发表后请及时关闭
from weekly.
Related Issues (20)
- 【自荐开源】AI可视化SolidUI HOT 2
- 精读《自由 + 磁贴混合布局》
- 请假一次 🏳️
- 精读《自由布局吸附线的实现》
- 请假一次 HOT 1
- 精读《算法题 - 通配符匹配》
- 这里我想是对应的 '*' 不匹配任何字符? HOT 1
- 精读《算法题 - 统计可以被 K 整除的下标对数目》
- 精读《算法题 - 最小覆盖子串》
- 请假一次
- 精读《算法题 - 地下城游戏》
- 请假一次 HOT 6
- 精读《VisActor 数据可视化工具》
- 精读《算法题 - 编辑距离》
- 请假一次
- 精读《算法题 - 二叉树中的最大路径和》
- 休刊一段时间 HOT 8
- 真的牛逼,竟然检测有病毒
- 【开源自荐】基于nextjs14,良好的体验、响应式、编码设计,开源了C-Shopping开源电商平台 HOT 7
- 第二季准备开更,内容预告! HOT 8
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from weekly.