$q:默认拒绝处理程序

$q: default reject handler

我想 return 一个 $q 实例,这样如果客户不使用拒绝处理程序调用 'then',那么将运行一个默认的。

例如假设默认值为 alert(1)

然后 mypromise.then(function(result){...}) 会提醒 1 但 mypromise.then(null, function(reason){alert(2)}) 会提醒 2

让我们假设有办法做到这一点。

所以我们有一台神奇的机器,它总能查明 .then 是否使用函数第二个参数调用来实现特定的承诺。

那又怎样?

所以你可以检测是否有人这样做了:

myPromise.then(..., function(){ F(); });

随时随地。并将 G() 作为默认操作。

还有……?

您可以将包含大量代码 P (1) 的整个程序转换为:

var myPromise = $q.reject();
P; // inline the program's code
myPromise.then(null, function(){}); // attach a handler

太好了,我可以做到,所以?

好吧,现在我们神奇的机器可以接受任意程序 P 并检测 myPromise 是否添加了拒绝处理程序。现在,当且仅当 P 不包含无限循环(即停止)时,才会发生这种情况。因此,我们检测是否添加了 catch 处理程序的方法是 reduced to the halting problem. Which is impossible(2)

所以通常 - 不可能检测到 .catch 处理程序是否曾经附加到承诺。

别胡说八道了,我要解决办法!

反响好!与许多问题一样,这个问题理论上 是不可能的,但在实践中很容易解决实际案例。这里的关键是启发式:

If an error handler is not attached within a microtask (digest in Angular) - no error handlers are ever attached and we can fire the default handler instead.

大致就是:你从不.then(null, function(){})异步。 Promise 是异步解决的,但处理程序通常是同步附加的,所以这很好用。

// keeping as library agnostic as possible.
var p = myPromiseSource(); // get a promise from source
var then = p.then; // in 1.3+ you can get the constructor and use prototype instead
var t = setTimeout(function(){ // in angular use $timeout, not a microtask but ok
    defaultActionCall(p);// perform the default action!
});
// .catch delegates to `.then` in virtually every library I read so just `then`
p.then = function then(onFulfilled, onRejected){
    // delegate, I omitted progression since no one should use it ever anyway.
    if(typeof onRejected === "function"){ // remove default action
        clearTimeout(t); // `timeout.cancel(t)` in Angular     
    }
    return then.call(this, onFulfilled, onRejected);
};

就这些了吗?

好吧,我只想补充一点,需要这种极端方法的情况很少见。在讨论向 io 添加拒绝跟踪时 - 一些人建议,如果没有 catch 的承诺被拒绝,那么整个应用程序可能会终止。所以要格外小心:)

(1) 假设 P 不包含变量 myPromise,如果它确实将 myPromise 重命名为 P 不包含的内容。

(2) 当然 - 可以说阅读 P 的代码就足够了,而不是 运行 它是为了检测 myPromise 获得拒绝处理程序.正式地说,我们将 P 中的每个 return 和其他终止形式更改为 return myPromise.then(null, function(){}) 而不是简单地将其放在最后。这样 "conditionality" 就被捕获了。