在promise链中吞噬了异常

时间:2016-01-17 23:12:50

标签: javascript parse-platform promise react-native

当Parse for React Native中的一系列promise中抛出异常时,我注意到发生了一些非常奇怪的事情。承诺链永远不会解决,永远不会拒绝,并且永远不会抛出异常。它只是默默地消失。

以下是重新创建问题的示例代码:

// Replacing this with Promise.resolve() prints the error.
// Removing this stage prints the error.
Parse.Promise.as()
  // Removing this stage causes a red screen error.
  .then(function() {
    // Replacing this with Parse.Promise.as() causes a red screen error.
    return Promise.resolve();
  })
  .then(function () {
    throw new Error("There was a failure");
  })
  .then(function () { console.log("Success")}, function (err) { console.log(err) });

从评论中可以看出,它似乎只发生在这个特定的事件序列中。删除一个阶段,或者交换一个原生JS承诺的Parse承诺,会导致事情再次发生。 (在我的实际代码中," Promise.resolve()"阶段实际上是对返回promise的本机iOS方法的调用。)

我知道Parse承诺不会像A +兼容的承诺那样完全(参见https://stackoverflow.com/a/31223217/2397068)。实际上,在此部分代码之前调用Parse.Promise.enableAPlusCompliant()会导致异常被捕获并打印。但我认为Parse promises和原生JS承诺可以安全地一起使用。

为什么这个异常会无声地消失?

谢谢。

2 个答案:

答案 0 :(得分:0)

除了您在引用答案中提供的技术原因之外,还需考虑您的考虑事项:

符合承诺

ES6 / A +兼容的Promise实例共享:

  1. 当承诺结算时,其结算的状态和价值是不可变的。
  2. 承诺不能兑现承诺。
  3. 当时注册的'fulfill'侦听器永远不会被promise(或其他可能的)对象作为参数调用。
  4. then注册的监听器在导致它们执行的代码运行完成后,在自己的线程中异步执行。
  5. 无论听众是否因为承诺被解决而被注册(“已履行”或“被拒绝”),

    • 侦听器的返回值用于履行 解决then注册所返回的承诺
    • 侦听器抛出的值(使用throw)用于拒绝then注册返回的承诺,
  6. 使用Promise实例解析的promise与自身的最终结算状态和作为参数提供的promise的值同步。 (在ES6标准中,这被描述为“锁定”)。

  7. 使用一个而不是一个Promise实例的可对象解析的promise将根据需要跳过同步:如果最初使用一个用一个thenable“完成”自己的thenable解决,那么Promise的承诺将重新开始 - 与最近提供的'thenable'同步自己。使用A + promises时,不能跳过一个新的可与之同步,因为它们从不用一个可用的对象调用一个“已完成”的监听器。
  8. 不合规承诺

    不合规承诺的潜在特征包括对象

    • 允许更改承诺的已解决状态,
    • 使用promise参数调用当时'履行'的侦听器,
    • 从解决或拒绝承诺的代码中同步调用当时的侦听器,用于“已完成”或“已拒绝”状态,
    • 在then then调用中注册的侦听器抛出异常后,不拒绝then返回的promise。

    互操作性

    Promise.resolve可用于通过静态值来解决其返回的promise,可能主要用于测试。然而,它的主要目的是隔离不合规承诺的副作用。 Promise.resolve( thenable)返回的承诺将展示上述所有行为1-7,并且不会出现任何违规行为。

    恕我直言我建议只在环境中使用非A + promise对象,并根据创建它们的库的文档。非兼容的thenable可用于直接解析A + promise(这是Promise.resolve所做的),但是为了完全可行的行为可预测性,它应该在任何其他用途之前使用Promise.resolve( thenable)包装在Promise对象中。 / p>

    注意我试图测试Parse承诺的A +合规性,但它似乎没有提供构造函数。这使得“几乎”或“完全”A +合规性的主张难以量化。感谢zangw指出可能会将拒绝的承诺作为一个侦听器返回,作为抛出异常的替代方法。

答案 1 :(得分:0)

  

为什么这个异常会消失?

Parse默认情况下不会捕获异常,并且promises会吞下它们。

Parse不是100%Promises / A +兼容,但它确实试图吸收从then回调返回的那些。它既不会捕获异常,也不会异步执行自己的回调。

您可以在没有then使用

的情况下复制您正在做的事情
var p1 = new Parse.Promise();
var p2 = new Parse.Promise();

// p2 should eventually settle and call these:
p2._resolvedCallbacks = [function (res) { console.log("Success") }];
p2._rejectedCallbacks = [function (err) { console.log(err) }];

function handler() {
    throw new Error("There was a failure");
}
// this is what the second `then` call sets up (much simplified):
p1._resolvedCallbacks = [function(result) {
    p2.resolve(handler(result)); // throws - oops
}];

// the native promise:
var p = Promise.resolve();
// what happens when a callback result is assimilated:
if (isThenable(p))
    p.then(function(result) {
        p1.resolve(result);
    });

问题是p1.resolve是同步的,并立即执行p1上的回调 - 这反过来会抛出。通过在可以调用p2.resolve之前投掷,p2将永远等待。异常冒泡并成为p1.resolve()的完成 - 现在抛出回调到本机then方法。本机promise实现捕获异常并拒绝then使用它返回的承诺,但是无处不在。

  

默默地?

如果您是" native" promise实现支持未处理的拒绝警告,您应该能够在被拒绝的承诺中看到异常。