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

Javascript 如何为一个承诺多次成功回调?,javascript,promise,Javascript,Promise,我有一个函数loadItems(),它异步加载一些东西,然后失败或成功。fail和success回调都必须在库中执行某些操作,然后将其传递给实现者,实现者可以选择实现fail、success、两者都执行,或者不执行 我现在遇到的问题是,如果库同时实现了成功和失败处理程序,它将始终返回一个新的承诺来解决成功问题 这就是我所拥有的: // The library: function loadItems() { return store.get('todo').then(function(rs

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

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

这就是我所拥有的:

// 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')
(来自另一个库)返回一个承诺<代码>加载项()无法控制它

// The library implementer:
function init() {
    loadItems().then(showItems);
}
我想要和期望发生的事情:

  • loadItems()
    从库中运行异步代码(
    store.get()
  • 它实现了
    成功
    失败
    ,因为它们具有强制操作
  • 它将成功/失败传递给实现者
  • 实现者只实现
    成功
    ,因为它不关心错误,因为库处理了错误
  • 因此它使用
    .then(onSuccess)
    来“添加另一个成功回调”
  • 会发生什么情况(出现错误):

  • 执行库的失败回调
  • 一个新的承诺传递给了实现者
  • 新的承诺总是成功的
  • 由于库的成功回调没有触发,因此触发了实现者的成功回调,结果不正确
  • 承诺真的太酷了以至于没有多个,sync成功处理程序吗

    我可以想象,即使是源代码库(定义
    store.get()
    )也希望处理错误(用于偷偷记录),然后传递成功/失败

    我的“解决方案”:

  • loadItems()
    ”失败回调引发错误。不幸的是,这意味着
    init()。不酷
  • 使用一个简单的回调来回话
    init()
    ,而不是承诺,承诺只在成功后才会触发。这不好,因为有一天
    init()
    可能会选择处理错误

  • 我肯定我做错了什么,但我看不出来。

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

    // 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);
        });
    }
    
    提供不抛出或返回被拒绝承诺的拒绝处理程序将告诉承诺系统您已“处理”错误,并且拒绝处理程序的返回值将成为承诺的新实现值。因此,如果您希望拒绝“保持”承诺,但希望处理程序根据拒绝做一些事情(记录拒绝是很常见的),那么您必须在拒绝处理程序中重新显示错误或返回被拒绝的承诺

    // 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);
        });
    }
    
    虽然这在一开始看起来可能违反直觉,但它为您提供了最大的灵活性,因为您可以完全处理错误并让返回的承诺“成功”得到解决,或者您可以选择告诉承诺系统您想要传播错误,甚至可以选择要传播的错误(不一定是相同的错误)


    你的问题中关于多个成功处理程序的部分让我有点困惑。你可以很容易地在任何承诺下拥有多个成功处理程序:

    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
    可以影响传递给
    他们的Handler
    的结果


    除了我的第一个建议,即重新引用错误,您还可以这样做:

    // 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()的已解析值或已拒绝错误,则可以执行此操作
    promise。我通常不建议这样做,因为如果处理程序正在执行其他异步操作或希望影响返回值,这会导致问题,但也可以在适当的情况下使用它。

    请阅读以下内容:您使用的是什么promise实现?“不幸的是,这意味着init()必须捕获它(或是浏览器抱怨)。不酷。“-不知道你的意思。拒绝承诺就像是这方面的一个例外,而这似乎正是你想要的?@CarlosCarucce我没有使用jQuery。@Bergi我在Chrome中使用本机承诺。我不想让每个“实现者”都处理错误,因为错误已经由
    loadItems()
    init()处理了
    只关心有效的结果。如果无效,则无所谓,但不要像有效一样执行
    then()
    。@Deux-这回答了你的问题吗?我尝试了最后一件事(返回原始承诺),但我仍然从Chrome收到“承诺中的未捕获错误”警告。我想这就是我想要的