GithubHelp home page GithubHelp logo

Comments (9)

camsong avatar camsong commented on April 28, 2024 4

reject 如果使用 Error 对象,会导致捕获不到错误的情况

@ascoders reject 使用 Error 对象指的是 reject(new Error('your message here'),并不是 throw。这样写比使用字符串优点是做统一错误处理时更加容易。使用 Promise 时要注意避免 try...catchthrow 的陷阱。

from weekly.

ascoders avatar ascoders commented on April 28, 2024 2

@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 住。

这是因为 setTimeoutthrow Error 无论如何都无法捕获到,而 rejectPromise 提供的关键字,自己当然可以 catch 住。

from weekly.

fanhc019 avatar fanhc019 commented on April 28, 2024 1

中文版译文地址:https://zhuanlan.zhihu.com/p/25338849

from weekly.

ascoders avatar ascoders commented on April 28, 2024

这篇文章核心介绍了 captureStackTrace 方法的使用,通过截取有意义报错堆栈,并统计上报,有助于排查问题。

常用的断言库 chai 就是通过此方式屏蔽了库自身的调用栈,仅保留了用户代码的调用栈,这样用户会清晰的看到自己代码的调用栈。

关于 V8性能优化 里提到,只要 try..catch 分离到单独函数中,引擎就可以优化代码,所以不用顾虑性能问题了。

from weekly.

jasonslyvia avatar jasonslyvia commented on April 28, 2024

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就可以
  });
});

image

不难看出,power-assert 不仅能给出清晰的调用栈,更能告诉你具体断言的每个变量值是什么。

from weekly.

camsong avatar camsong commented on April 28, 2024

这篇文章里提出了一些异常处理的技巧,重要的一点是 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.

fanhc019 avatar fanhc019 commented on April 28, 2024

文章开篇部分就讲解了 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.stacke 类似。感兴趣的可以了解下 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.

ascoders avatar ascoders commented on April 28, 2024

对,补充一点,我也很反对 chai 的断言方式,过分语义化反而让代码更难读,有一种在使用 易语言
的感觉:

should(obj.arr[0]).be.equal(obj.number)

所以,我支持 avajs 的方式:

test.true(1 === count)
test.is(str, 'ok')

from weekly.

ascoders avatar ascoders commented on April 28, 2024

专栏发表后请及时关闭

from weekly.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.