【问题标题】:Why does reject() of a new Promise loses stack trace in the dreaded "Uncaught (in promise)" error为什么新承诺的拒绝()在可怕的“未捕获(承诺中)”错误中丢失堆栈跟踪
【发布时间】:2018-03-31 12:45:05
【问题描述】:

在 Angular 的 github 问题、google 或在 stackoverflow 上搜索“Uncaught (in promise)”会产生很多非常具体的结果,但我的问题有点广泛(而且由于结果的扩散,我不知道这是否是重复的)

前提:在我的代码中某处我有一个未捕获的承诺拒绝(Angular 4.4.4)

案例:

案例 1:简单拒绝

在我的组件中:

ngOnInit() {
    Promise.reject("foo");
}

在控制台中产生这个(太好了,我可以看到它来自哪里):

ERROR Error: Uncaught (in promise): foo
    at resolvePromise (zone.js:824)
    at Function.ZoneAwarePromise.reject (zone.js:903)
    at MyComponent.webpackJsonp.../../../../../src/app/component/my.component.ts.MyComponent.ngOnInit (my.component.ts:nn)

案例2:新的Promise,抛出错误

在我的组件中:

ngOnInit() {
  new Promise((resolve, reject) => {
    throw new Error("foo");
  }).then(() => {
    console.log("ain't gonna happen");
  });
}

在控制台中产生这个(更好的是,当场给出位置):

ERROR Error: Uncaught (in promise): Error: foo
Error: foo
    at my.component.ts:nn
    at new ZoneAwarePromise (zone.js:890)
    at MyComponent.webpackJsonp.../../../../../src/app/component/my.component.ts.LMyComponent.ngOnInit (my.component.ts:nn)

这也适用于链接,例如以下在控制台中或多或少地给出了相同的堆栈跟踪。

ngOnInit() {


  const promise3 = new Promise((resolve, reject) => {
    throw new Error("baz");
  });
  const promise2 = new Promise((resolve, reject) => {
    resolve(promise3);
  });

  const promise1 = new Promise((resolve, reject) => {
    resolve(promise2);
  });

  promise1.then(p1=> console.log(p1));
}

案例3:使用reject(...)

在我的组件中:

ngOnInit() {
  new Promise((resolve, reject) => {
    reject("foo");
  }).then(() => {
    console.log("ain't gonna happen");
  });
}

将抛出错误更改为使用 promise 的拒绝方法(我认为这是很常见的做法),会产生这种恐怖:

core.es5.js:1020 ERROR Error: Uncaught (in promise): baz
    at resolvePromise (zone.js:824)
    at resolvePromise (zone.js:795)
    at zone.js:873
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425)
    at Object.onInvokeTask (core.es5.js:3881)
    at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:424)
    at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask (zone.js:192)
    at drainMicroTaskQueue (zone.js:602)
    at <anonymous>

问题

  1. 为什么这次我看不到堆栈跟踪或错误的根源? (我认为这是由于 JavaScript 仅从抛出错误的位置生成堆栈跟踪?)

  2. 如果是这样,使用显式拒绝而不是在新 Promise 中抛出新错误是不好的做法吗?它是否记录在某处而我错过了?

  3. 有没有办法解决这个问题? (获取堆栈跟踪并继续使用拒绝(...)而不是抛出错误?,我假设没有)

  4. 这是一个众所周知的问题/不好的做法,我只是错过了备忘录吗?

【问题讨论】:

标签: javascript angular es6-promise


【解决方案1】:

部分回答我自己的一个问题:

如果我将 case #3 更改为:(包装在一个新的 Error 对象中)

ngOnInit() {
  new Promise((resolve, reject) => {
    reject(new Error("foo"));
  }).then(() => {
    console.log("ain't gonna happen");
  });
}

然后,令人惊讶的是,我确实得到了堆栈跟踪! (仅仅构造一个错误可以保存堆栈跟踪)

附带说明...因为(我猜)我们大多数人更喜欢查看堆栈跟踪而不是不查看,那么为什么哦,为什么这里没有将其作为最佳实践提到呢?:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

编辑

为了确保我不会忘记,我添加了这个缩小范围(reject: (reason: Error) =&gt; void 而不是any),不确定这是否是一个很好的解决方案,因为它不能防止通过any,但它可以帮助保护一些不通过Error 拒绝的情况。

export {}

declare global {

  interface PromiseConstructor {
    /**
     * A reference to the prototype.
     */
    readonly prototype: Promise<any>;

    /**
     * Creates a new Promise.
     * @param executor A callback used to initialize the promise. This callback is passed two arguments:
     * a resolve callback used resolve the promise with a value or the result of another promise,
     * and a reject callback used to reject the promise with a provided reason or error.
     */
    new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason: Error) => void) => void): Promise<T>;

  }
}

【讨论】:

  • 糟糕,没有看到@Bergi 的评论正是这么说的。保持清晰...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-21
  • 2021-12-22
  • 1970-01-01
  • 2017-02-21
相关资源
最近更新 更多