为什么我的ES6 Promise Rejection需要立即使用以避免出现控制台错误消息?

Ste*_*n G 5 javascript cross-browser ecmascript-6 es6-promise

请注意:以下是在不同浏览器上表现不同的问题.所以这可能是一个浏览器实现问题.无论如何,我会喜欢一些建议.

在我的应用程序中,我创建了一些承诺,我可能不会消费,直到将来很长一段时间.哪个应该没问题,毕竟它们是承诺.

如果解决了存储的承诺,则没有问题.我可以根据自己的需要尽可能多地消费它,也可以随心所欲地消费它.正如所料.

但是,如果被拒绝的承诺被拒绝,则存在问题.除非我在制作完成后立即消除拒绝(不确定多久),否则Chrome或Firefox中会出现一个控制台消息,表明存在未被拒绝的承诺拒绝/错误.IE不会弹出该错误.

请考虑以下代码:

console.log("About to make a promise rejection.");
var foo = Promise.reject(new Error("Foo Rejected Promise."));
console.log("Promise rejection made.");
Run Code Online (Sandbox Code Playgroud)

请注意,没有使用或消费promise foo.它只是存储起来以备将来使用.

IE上的控制台如下所示:

即将拒绝承诺.

承诺拒绝.

这是预期的.但是,Chrome上的相同代码将生成以下控制台:

即将拒绝承诺.

承诺拒绝.

未捕(承诺)错误:Foo拒绝承诺.(...)

除了围绕"未捕获"错误的措辞之外,Firefox看起来非常像Chrome.

但问题是,我打算在很久以后处理这个"错误",当时我正在消费这个承诺.仅仅有一个被拒绝的承诺不应该导致控制台错误.....如果我使用了承诺并且没有处理错误,那么应该会发生.

要模拟错误的"更晚"处理,请考虑对代码的这种更改:

console.log("About to make a promise rejection.");
var foo = Promise.reject(new Error("Foo Rejected Promise."));
console.log("Promise rejection made.");
setTimeout(() => {
    foo.catch((err) => {
        console.log("Displaying " + err.message + " 10 seconds later.");
    });
}, 10000);
Run Code Online (Sandbox Code Playgroud)

现在在这种情况下,我们通过在超时后在控制台上显示某些内容来"处理"错误.现在IE仍然按照我的预期处理这个:

即将拒绝承诺.

承诺拒绝.

显示Foo拒绝的承诺.10秒后

在这种情况下,Firefox确实喜欢IE,并准确显示这些消息,并没有给我一个错误的控制台错误.

但是,Chrome仍会出现错误错误:

即将拒绝承诺.

承诺拒绝.

未捕(承诺)错误:Foo拒绝承诺.(...)

显示Foo拒绝的承诺.10秒后

所以Chrome都抱怨我的错误没有被处理,然后显示它已被处理.

似乎我可以使用以下代码来解决这一切,这看起来像是一个黑客.基本上我在创建promise时对错误进行"假"处理,然后以我想要的方式真正处理它:

console.log("About to make a promise rejection.");
var foo = Promise.reject(new Error("Foo Rejected Promise."));
foo.catch(() => { });  // Added this hack-ish code.
console.log("Promise rejection made.");
    setTimeout(() => {
    foo.catch((err) => {
        console.log("Displaying " + err.message + " 10 seconds later.");
    });
}, 10000);
Run Code Online (Sandbox Code Playgroud)

但这是丑陋的代码.

我的问题是双重的 - 是否有某种方式来看待Chrome(以及某种程度上FireFox)正在做什么并将其视为一种恩惠?因为对我而言似乎很糟糕.其次,当你不是假装处理错误的黑客时,是否有更好的解决方法呢?

提前致谢.

Est*_*ask 3

任何有可能被拒绝的承诺都应该像异常一样进行处理。

承诺不会被同步链接的机会并不多。但如果不会,则需要“hack-ish”.catch(() => { })来同步处理拒绝。

Chrome 承诺拒绝行为表明了这一点

var foo = Promise.reject(new Error("Foo Rejected Promise."));
foo.catch(() => { });  // Added this hack-ish code.

setTimeout(() => {
    foo.catch((err) => {
        console.log("Displaying " + err.message + " 10 seconds later.");
    });
}, 10000);
Run Code Online (Sandbox Code Playgroud)

进入同一个错误处理船

try {
  throw new Error("Foo"));

  setTimeout(() => {
    try {
      throw new Error("Foo"));
    } catch (err) {
      console.log("Displaying " + err.message + " 10 seconds later.");
    }
  }, 10000);
} catch (err) {}
Run Code Online (Sandbox Code Playgroud)

异常不是要等10秒才能被next捕获try...catch然后抛出吗?它甚至不会等待一个滴答声。它需要“hack-ish”try { ... } catch (err) {}块才能按预期执行。

Bluebird 库用户长期以来已经熟知这种行为。Bluebird 具有可调整的错误处理功能,即使在大规模情况下也可以高效地调试 Promise 。

这种行为在 Angular 2 开发中也是众所周知的,它是强制使用 Zone.js 库进行承诺的。

由于 Promise 调试的价值有限并且适用于开发环境,因此可以在生产构建中修改或禁用本机 Promise 的此行为:

if (typeof DEBUG_PROMISE === 'undefined') {
  window.addEventListener('unhandledrejection', (e) => {
    e.preventDefault();
    console.warn(e.reason);
  });
}
Run Code Online (Sandbox Code Playgroud)

这是有关该主题的更多阅读内容。