如何调试 javascript 承诺?

Posted

技术标签:

【中文标题】如何调试 javascript 承诺?【英文标题】:How to debug javascript promises? 【发布时间】:2014-11-07 18:01:41 【问题描述】:

我正在尝试了解如何调试基于 Promise 的异步代码。承诺是指基于 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?

【问题讨论】:

基于html5rocks.com/en/tutorials/es6/promises 我宁愿这样做:reject('Error') 但你能发布一个 jsfiddle 以便我们有一些具体的工作吗? 这是使用 Bluebird Promise 库的主要优势之一。只要您的承诺代码中有未处理的拒绝或异常,它就会为您捕获堆栈跟踪。我一直在将它与 node.js 一起使用,它节省了大量时间。老实说,我不知道如何通过内置的 Promise 获得相同的功能。 @Renra 请不要给出不好的建议 - 抛出(或拒绝)原语是一种令人讨厌的习惯,会使调试变得更加困难。 ***.com/questions/43834559/… 【参考方案1】:

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

在 Chrome 中调试原始 ES6 承诺是可怕的。这是因为它们会静默地抑制错误,并且无论何时您忽略一个 catch,它都不会向您提供任何承诺失败的迹象。 更新:Chrome 现在记录未处理的拒绝 (see this link for how)

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

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

那么,有什么办法呢?

包括 Bluebird - 它是 ES6 承诺的超集,您可以直接在内部交换它,它具有更丰富的 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。就我个人而言,我很重视知道我在生产中存在错误,所以我不推荐它,但它肯定是可行的。

【讨论】:

可能会减慢它的原因是它必须在代码中标记每个行号以用于制作堆栈,这会使更长的代码稍微多一些。尽管为了调试,这绝对值得放慢速度。 嗯,它需要将堆栈跟踪缝合在一起,但仅在错误时 - 通常 Bluebird 非常快,并且在客户端长堆栈跟踪时性能仍然非常好。 非常感谢您的回答,至少现在我知道我不是唯一一个为此苦苦挣扎的人。肯定会调查蓝鸟。此外,将尝试制作一个 JSFiddle 来说明当 Promise 失败时不会显示任何错误。除此之外 - 发生错误的承诺实际上可能会显示其状态为“已解决”,我认为如果承诺不是链中的最后一个,就会发生这种情况。 蓝鸟!惊人的。哇。我正在使用 Q 并且非常沮丧。 是的,Chrome 实际上有一个很好的承诺调试面板即将推出 :) 在金丝雀很快,然后会更新【参考方案2】:

这个答案是对 Benjamin Gruenbaum 答案的补充: 如果在 Promise 链中使用 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)

【讨论】:

谢谢,错过了stack 属性,想知道它去了哪里,哈哈! 只是重申这一点......我被console.log(err) 不包括err.stack 的事实所愚弄。您需要console.log(err.stack) 才能查看详细信息。 直到我勾选了山羊回答中提到的“异步”复选框,它才对我有用。 ***.com/a/25827268/247696【参考方案3】:

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

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

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

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

【讨论】:

它仍然不会将错误打印到控制台,也不会提供有关错误发生位置的任何信息。我所说的错误是指您没有“计划”捕获的东西,例如键入可能在承诺中发生的错误等。 一个类型错误应该出现在控制台中,即使是在一个promise中。 @dandavis 不会的。 谷歌浏览器现在默认支持异步调用堆栈,并删除了复选框:developers.google.com/web/updates/2017/05/…【参考方案4】:

他们似乎正在使用 Chrome 中的调试工具。有关详细信息,请参阅此主题。

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

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

【讨论】:

我现在在 Chrome 中看不到任何特定于 Promise 的调试工具。你呢? Google 几个月前删除了该功能。请尝试使用异步助手。 see this commitAbout async debugging【参考方案5】:

调试承诺的最佳方式是监听processunhandledRejection 事件。

例如,您可以在这里设置它并转储堆栈跟踪...

 process.on('unhandledRejection', (reason, p) => 
   console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
   // Stack Trace
   console.log(reason.stack);
 );

【讨论】:

你会把那个代码放在哪里?我的承诺有误,甚至无法找到要查看的文件...【参考方案6】:

在返回Promise对象时在.then()函数内部, 添加console.log() 声明。 如果需要,请在 .catch() 内部执行相同操作:

...
  .then(
  (docs) =>
      console.log(docs); ==> put here
      resolve(docs);
  )
  .catch((e)=>

【讨论】:

以上是关于如何调试 javascript 承诺?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Mocha 测试中调试“错误:无理由或错误理由拒绝承诺”?

在 JavaScript 中,如何在超时中包装承诺?

Javascript,如何等待多个承诺[重复]

如何承诺 AWS JavaScript 开发工具包?

如何在Javascript中制作精确的睡眠功能,可能使用承诺?

Mac中用于WebStorm的Javascript文件