如何为1个承诺多次成功回调?

时间:2016-01-26 18:46:27

标签: javascript promise

我有一个函数loadItems(),可以加载异步,然后失败或成功。失败和成功回调都必须在库中执行某些操作,然后将其传递给实现者,实现者可以选择实现失败,成功,或两者,或者不执行任何操作。

我现在遇到的问题是,如果库同时实现了成功和失败处理程序,它将始终返回一个解除成功的新承诺。

这就是我所拥有的:

// The library:
function loadItems() {
    return store.get('todo').then(function(rsp) {
        // Save these locally
        items = rsp.value || [];
    }, function(rsp) {
        // Do nothing, but let the user know
        alert(rsp.error);
    });
}

store.get('todo')(来自另一个库)返回一个承诺。 loadItems()无法控制它。

// The library implementer:
function init() {
    loadItems().then(showItems);
}

我想要什么,并且预计会发生什么:

  1. loadItems()运行库中的异步代码(store.get()
  2. 它实施successfail,因为它们具有强制性操作
  3. 将成功/失败传递给实施者
  4. 实施者只实现success,因为它不关心错误,因为库处理它
  5. 因此它使用.then(onSuccess)来“添加另一个成功回调”
  6. 反而发生了什么(有错误):

    1. 执行库的故障回调
    2. 新承诺传递给实施者
    3. 新承诺始终取决于成功
    4. 执行者的成功回调被触发,结果破坏,因为库的成功回调没有触发
    5. Promise是否真的太酷了,无法拥有多个同步成功处理程序?

      我可以想象,即使源库(定义{{​​1}})想要处理错误(用于偷偷摸摸地记录),然后传递成功/失败。

      我的'解决方案':

      1. store.get()'失败回调抛出错误。不幸的是,这意味着loadItems()必须抓住它(或浏览器抱怨它)。不酷。
      2. 使用简单的回调来回复init(),而不是仅在成功后触发的承诺。这不好,因为init() 可能选择在某一天处理错误。
      3. 我确定我做错了什么,但我没有看到。

1 个答案:

答案 0 :(得分:2)

如果您希望让拒绝处理程序根据错误执行某些操作,但希望仍然拒绝返回的承诺,则只需在拒绝处理代码后重新抛出错误(或返回拒绝的承诺)。这将允许拒绝通过返回的promise传播回来。

// The library:
function loadItems() {
    return store.get('todo').then(function(rsp) {
        // Save these locally
        items = rsp.value || [];
    }, function(rsp) {
        // Do nothing, but let the user know
        alert(rsp.error);
        // rethrow the error so the returned promise will still be rejected
        throw(rsp);
    });
}

提供不抛出或返回被拒绝的承诺的拒绝处理程序告诉承诺系统您已经处理了#34;拒绝处理程序的错误和返回值将成为promise的新履行值。所以,如果你想要承诺"留下"被拒绝了,但是希望有一个处理程序根据拒绝做一些事情(记录拒绝很常见),那么你必须重新抛出拒绝处理程序中的错误或者返回被拒绝的承诺。

虽然这最初看起来可能是违反直觉的,但它可以为您提供最大的灵活性,因为您可以完全处理错误并让返回的承诺得到解决并成功地#34;或者你可以选择告诉promise系统你想要传播一个错误,你甚至可以选择你想要的错误(它不一定是同一个错误)。

关于多个成功处理程序的问题部分对我来说有点混乱。您可以轻松拥有多个成功处理程序,并承诺:

var p = someFuncThatReturnsSuccessfulPromise();
p.then(someSuccessHandler);
p.then(someOtherSuccessHandler);

如果p是成功解决的承诺,那么这两个成功处理程序将按照附加顺序进行调用,someSuccessHandler中发生的事件对someOtherSuccessHandler是否会产生影响是否被召唤。如果原始承诺成功解决,则将始终调用两个处理程序。

如果您将成功处理程序链接起来,那么这是一个完全不同的用例。这完全不同:

var p = someFuncThatReturnsSuccessfulPromise();
p.then(someSuccessHandler).then(someOtherSuccessHandler);

因为第二个.then()处理程序未附加到p,而是附加到p.then(someSuccessHandler),这是一个不同的承诺,其结果可能会受到someSuccessHandler中发生的事情的影响

您问题中的代码是链接的。你要回来了:

 return store.get().then(...)

因此,当调用者链接到那个时,整个链是:

 return store.get().then(yourhandler).then(theirhandler)

通过这种方式,yourhandler可以影响传递给theirhandler的结果。

除了我第一次只是重新抛出错误的建议之外,您还可以这样做:

// The library:
function loadItems() {
    var p = store.get('todo');
    p.then(function(rsp) {
        // Save these locally
        items = rsp.value || [];
    }, function(rsp) {
        // Do nothing, but let the user know
        alert(rsp.error);
    });
    return p;
}

在这里,您可以确保您的处理程序不会影响返回的内容。如果您在处理程序中没有任何异步操作,并且您没有尝试更改原始store.get()承诺的已解决值或拒绝错误,则可以执行此操作。我通常不建议这样做,因为如果您的处理程序正在执行其他异步操作或想要影响返回值,则会导致问题,但它也可以在适当的情况下使用。