79

我试图了解如何调试基于承诺的异步代码。承诺是指基于 ECMAScript 6 的承诺,而调试是指使用内置的 chrome 或 firefox 调试器。

我遇到的问题是,当发生错误时,无论我如何“拒绝”它,我似乎都无法获得堆栈跟踪。

我试过这些:

console.log(new Error('Error occured'));
throw new Error('Throwing an Error');
return new Error('Error returned by the onRejected function');
reject(new Error('Pass Error to the reject function'));

但是这些都没有返回代码中的实际错误或堆栈跟踪。

所以我的问题是 - 如何正确调试 javascript Promises?

4

6 回答 6

64

这是一个值得讨论的好话题,可悲的是,对于原生承诺来说,这实际上是相当困难的。

在 Chrome 中调试原始 ES6 承诺是可怕的。这是因为它们会默默地抑制错误,并且无论何时你省略了一个 catch,它都不会给你任何承诺失败的迹象。更新:Chrome 现在记录未处理的拒绝(请参阅此链接了解如何)

 Promise.resolve("foo").then(function(){
      throw new Error("You will never see this");// silent failure
 });

在 Firefox 中,情况要好一些,因为它们执行未处理的拒绝检测 - 但是,它仍然很不稳定,如果你将承诺分配到任何地方,它就不会起作用。

那么,可以做些什么呢?

包括Bluebird——它是 ES6 Promise 的超集,你可以直接在里面交换它​​,它有更丰富的 API,速度更快,并且有惊人的堆栈跟踪。它在构建时考虑到了调试,并包括出色的错误处理工具。

包含 Bluebird 后,请致电:

Promise.longStackTraces();

这会减慢它的速度(它仍然会非常快)并且会给你惊人的错误信息。例如:

Promise.resolve().then(function outer() {
    return Promise.resolve().then(function inner() {
        return Promise.resolve().then(function evenMoreInner() {
            a.b.c.d()
        });
    });
});

在本机承诺中 - 这将是一个静默失败,并且很难调试 - 使用 Bluebird 承诺,默认情况下这将在您的控制台中显示一个大的红色错误,为您提供:

ReferenceError: a is not defined
    at evenMoreInner (<anonymous>:6:13)
From previous event:
    at inner (<anonymous>:5:24)
From previous event:
    at outer (<anonymous>:4:20)
From previous event:
    at <anonymous>:3:9
    at Object.InjectedScript._evaluateOn (<anonymous>:581:39)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:540:52)
    at Object.InjectedScript.evaluate (<anonymous>:459:21)

完成调试后 - 您可以将其换掉并返回到原生 Promise。就我个人而言,我很重视知道我在生产中有错误,所以我不推荐它,但它肯定是可行的。

于 2014-09-14T07:56:16.897 回答
14

这个答案是对 Benjamin Gruenbaum 答案的补充:如果您在承诺链中使用 catch 语句,您将通过error.stack获得堆栈跟踪:

        Promise.longStackTraces();

        function outer() {
            return Promise.resolve();
        }

        function inner() {
            return Promise.resolve();
        }

        function evenMoreInner() {
            a.b.c.d()
        }

        Promise.resolve()
            .then(outer)
            .then(inner)
            .then(evenMoreInner())
            .catch(function (err) {
                    console.log(err.message);
                    console.log(err.stack);
                });

错误信息:

ReferenceError: a is not defined
at evenMoreInner (test/test_promise.js:58:17)  <<<< HERE's the error!
at Context.<anonymous> (test/test_promise.js:64:23)
于 2015-11-29T07:47:59.333 回答
13

*这并不能直接回答您的问题,但它可能会有所帮助。

Chrome devtools 最近获得了一项新功能,可用于调试异步代码,例如 Promises。

http://www.html5rocks.com/en/tutorials/developertools/async-call-stack/

基本上,启用源选项卡中的“异步”复选框,Chrome 将为您重建调用堆栈,就好像它是同步代码一样。

截屏

于 2014-09-13T20:15:48.560 回答
1

他们似乎正在使用 Chrome 中的调试工具。有关更多信息,请参阅此线程。

https://code.google.com/p/v8/issues/detail?id=3093

我还没有检查这是否已经在开发版或测试版中,但我希望它会很快。然后它可能会在 2015 年 1 月左右包含在正常版本中(只是个人猜测,绝对没有保证,因为我什至不为 Google 工作)。

于 2014-11-27T14:25:46.653 回答
1

调试承诺的最好方法是监听unhandledRejection你的process.

例如,以下是您可以如何设置它并转储堆栈跟踪...

 process.on('unhandledRejection', (reason, p) => {
   console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
   // Stack Trace
   console.log(reason.stack);
 });
于 2017-12-08T18:34:16.257 回答
1

在返回Promise对象.then()时,在函数内部 添加一条语句。如果需要 ,在里面做同样的事情:
console.log()
.catch()

...
  .then(
  (docs) =>{
      console.log(docs); ==> put here
      resolve(docs);
  })
  .catch((e)=>{
于 2018-07-05T21:19:17.710 回答