【问题标题】:Promise reject() causes "Uncaught (in promise)" warningPromise reject() 导致“Uncaught (in promise)”警告
【发布时间】:2017-02-25 18:35:33
【问题描述】:

一旦调用了 promise reject() 回调,Chrome 控制台中就会出现警告消息“Uncaught (in promise)”。我无法理解背后的原因,也无法摆脱它。

var p = new Promise((resolve, reject) => {
  setTimeout(() => {
    var isItFulfilled = false
    isItFulfilled ? resolve('!Resolved') : reject('!Rejected')
  }, 1000)  
})

p.then(result => console.log(result))
p.catch(error => console.log(error))

警告:

编辑:

我发现如果onRejected处理程序没有显式提供给.then(onResolved, onRejected)方法,JS会自动提供一个隐式处理。它看起来像这样:(err) => throw err。自动生成的处理程序将轮流抛出。

参考:

如果 IsCallable(onRejected)` 为 false,则
onRejected 为“Thrower”。

http://www.ecma-international.org/ecma-262/6.0/index.html#sec-performpromisethen

【问题讨论】:

  • 看来您正在使用 Angular 的 ZoneAwarePromise。他们错误地实施了拒绝处理,至少在特定版本中是这样。 但请记住,从 Fulfillment Handler(然后是 arguments[0])返回的 anything 将更改方法链接的结果,以便下一个 then 调用来自一个新的 Promise 并返回作为[潜在]状态的值.

标签: javascript promise es6-promise catch-block


【解决方案1】:

发生这种情况是因为您没有将 catch 处理程序附加到第一个 then 方法返回的 Promise 上,因此当 Promise 拒绝时,它没有处理程序。你确实在最后一行有一个承诺p,但在它之前的行中没有一个由then 方法返回的chained承诺。

正如您在下面的 cmets 中正确添加的那样,当未提供 catch 处理程序(或它不是函数)时,default one will throw 错误。在 Promise 链中,可以通过 catch 方法回调捕获此错误,但如果没有,JavaScript 引擎将像处理任何其他未捕获的错误一样处理该错误,并在这种情况下应用默认处理程序,这将导致您在控制台中看到的输出。

为避免这种情况,请将.catch 方法链接到第一个then 返回的承诺,如下所示:

p.then( result =>  console.log('Fulfilled'))
 .catch( error =>  console.log(error) );

【讨论】:

  • 谢谢 trincot。我做了一些额外的研究,发现如果 onRejected 处理程序没有显式传递,JS 将提供一个隐式处理程序:If IsCallable(onRejected) is false,然后让 onRejected 为 "Thrower”。看起来像这样:arg => throw arg 一个空的 onRejected 处理程序 () => {} 可以覆盖此行为。但是null 不会。 参考:ecma-international.org/ecma-262/6.0/…
  • 不客气,很好地参考了 EcmaScript 规范!为了完整起见,我将此添加到我的答案中。太好了!
  • @trincot 我把它锁起来了,它仍然给我未捕获的错误消息
  • @AmritKahlon,那么您可能还有其他事情要做。如果您已经研究过该问题(通过调试、寻找类似问题……),请发布一个新问题。
  • @GarfieldKlon,如果您不仅想捕获对原始承诺 p 的拒绝,而且还想在 then 回调中捕获异常(拒绝承诺由then() 返回)。通常,当您执行p.then(...).then(...).then(...).then(...).catch(...) 时,您会在承诺链中的任何地方发现拒绝。
【解决方案2】:

即使您正确使用 Promises:p.then(p1).catch(p2),如果您的 p2 函数最终抛出您打算使用诸如 window.onerror 之类的机制捕获的异常,您仍然可以获得未捕获的异常。原因是堆栈已经被 promise 中的错误处理解开。要解决此问题,请确保您的错误代码(由拒绝函数调用)不会引发异常。它应该简单地返回。

如果错误处理代码可以检测到堆栈已经被展开(因此您的错误调用不必为这种情况提供标志),那将是很好的,如果有人知道如何轻松地做到这一点,我会编辑此答案以包含该解释。

【讨论】:

  • “如果错误处理代码可以检测到堆栈已经被展开”then 回调总是如此:它总是异步运行。
【解决方案3】:

此代码不会导致“未捕获的承诺”异常:

// Called from top level code; 
// implicitly returns a Promise
testRejectCatch = async function() {

    // Nested within testRejectCatch;
    // simply rejects immediately
    let testReject = function() {
        return new Promise(function(resolve, reject) {
            reject('test the reject');
        )};
    }
 
//***********************************************
// testRejectCatch entry.
//***********************************************
try {
    await testReject(); // implicitly throws reject exception
catch(error) {
    // somecode 
 }

//***********************************************
// top level code
//***********************************************
try{
    testRejectCatch()   // Promise implicitly returned,
    .catch((error) => { // so we can catch
        window.alert('Report error: ' + error);
       // must not throw error;
    });
}
catch(error) {
    // some code
}

说明: 首先,有一个术语问题。 “抓”这个词是 以两种方式使用:在 try-catch 和 Promise 中。 因此,很容易对“投掷”感到困惑;是不是在扔 尝试捕获还是 Promise 捕获?

Answer: testReject 中的reject 是扔给Promise 的 隐式捕获,等待测试拒绝;然后扔到 testRejectCatch() 处的 .catch。

在这种情况下,try-catch 无关紧要并被忽略; 投掷与他们无关。

testRejectCatch 处的 .catch 满足要求 必须在某个地方接住最初的投掷, 这样您就不会遭受“未捕获的 Promise...”异常。

要点:Promises 的 throws 是 throws 到 .catch, 不要尝试捕捉;并且必须在一些.catch中处理

编辑: 在上面的代码中,拒绝通过 .catch 向上传播。 如果你愿意,你可以转换为传播 try-catch。 在第 17 行,将代码更改为:

let bad = '';
await testReject().catch((error) => {bad = error});
if (bad) throw bad;

现在,您已切换到 try-catch。

【讨论】:

    【解决方案4】:

    我遇到了这个问题,但是没有 setTimeout()

    如果其他人遇到这种情况:如果在 Promise 构造函数中你只是同步调用 reject(),那么无论你添加多少 .then().catch() 处理程序到返回的 Promise,它们都不会' t 防止未捕获的 Promise 拒绝,因为 Promise 拒绝会发生在你之前

    【讨论】:

      【解决方案5】:

      我已经在我的项目中解决了这个问题,这是一个大型企业项目。我的团队懒得写空catch几百次了。

      Promise.prototype.then = function (onFulfilled, onRejected) {
          return baseThen.call(this, (x: any) => {
              if (onFulfilled)
                  onFulfilled(x);
          }, (x: any) => {
              if (onRejected)
                  onRejected(x);
          });
      };
      

      【讨论】:

      • 这正是你不应该为一个懒惰的团队做的事情。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-26
      • 2019-12-20
      • 2021-04-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多