首页 文章

什么是明确的承诺构建反模式,我该如何避免它?

提问于
浏览
400

我编写的代码看起来像:

function getStuffDone(param) {           | function getStuffDone(param) {
    var d = Q.defer(); /* or $q.defer */ |     return new Promise(function(resolve, reject) {
    // or = new $.Deferred() etc.        |     // using a promise constructor
    myPromiseFn(param+1)                 |         myPromiseFn(param+1)
    .then(function(val) { /* or .done */ |         .then(function(val) {
        d.resolve(val);                  |             resolve(val);
    }).catch(function(err) { /* .fail */ |         }).catch(function(err) {
        d.reject(err);                   |             reject(err);
    });                                  |         });
    return d.promise; /* or promise() */ |     });
}                                        | }

有人告诉我这个被分别称为“ deferred antipattern " or the " Promise constructor antipattern ”,这段代码有什么不好,为什么这叫做antipattern

2 回答

  • 272

    Esailija创造的deferred antipattern (now explicit-construction anti-pattern)是一个普通的反模式的人,他们是新的承诺,我在我第一次使用承诺时自己做了 . 上述代码的问题在于未能利用promises链的事实 .

    Promise可以与 .then 链接,你可以直接返回promises . 您在 getStuffDone 中的代码可以重写为:

    function getStuffDone(param){
        return myPromiseFn(param+1); // much nicer, right?
    }
    

    Promise都是为了使异步代码更具可读性,并且表现得像同步代码而不隐藏这一事实 . Promise表示对一次性操作的值的抽象,它们在编程语言中抽象出语句或表达式的概念 .

    您应该只在converting an API to promises时使用延迟对象,并且可以't do it automatically, or when you'重新编写更容易用这种方式表达的聚合函数 .

    引用Esailija:

    这是最常见的反模式 . 当你不真正了解承诺并将它们视为美化事件 Launcher 或回调实用程序时,很容易陷入这种情况 . 让我们回顾一下:promises是关于使异步代码保留同步代码的大部分丢失属性,例如扁平缩进和一个异常通道 .

  • 98

    它出了什么问题?

    但模式有效!

    幸运的你 . 不幸的是,它可能没有,因为你可能忘记了一些边缘情况 . 在我看过的一半以上的事件中,作者忘记了处理错误处理程序:

    return new Promise(function(resolve) {
        getOtherPromise().then(function(result) {
            resolve(result.property.example);
        });
    })
    

    如果另一个承诺被拒绝,这将被忽视而不是传播到新的承诺(它将被处理) - 并且新的承诺永远待决,这可能导致泄漏 .

    在你的回调代码导致错误的情况下会发生同样的事情 - 例如当 result 没有 property 时会抛出异常 . 那将是未经处理的,并且未能解决新的承诺 .

    相反,使用 .then() 会自动处理这两种情况,并在发生错误时拒绝新的承诺:

    return getOtherPromise().then(function(result) {
         return result.property.example;
     })
    

    延迟的反模式不仅麻烦,而且 error-prone . 使用 .then() 进行链接更加安全 .

    但我已经处理了一切!

    真?好 . 但是,这将非常详细和丰富,特别是如果您使用支持其他功能(例如取消或消息传递)的promise库 . 或者也许它将来,或者你想要将你的图书馆换成更好的图书馆?您不希望为此重写代码 .

    库的方法( then )不仅本身支持所有功能,它们也可能具有某些优化 . 使用它们可能会使您的代码更快,或者至少可以通过库的未来版本进行优化 .

    如何避免它?

    因此,每当您发现自己手动创建 PromiseDeferred 并且涉及已经存在的承诺时, check the library API first . 延迟反模式通常由那些将promises [仅]视为观察者模式的人应用 - 但是promises are more than callbacks:它们应该是可组合的 . 每个体面的图书馆都有许多易于使用的功能,以各种可想象的方式构成承诺,处理你不想处理的所有低级别的东西 .

    如果您发现需要以现有帮助函数不支持的新方式编写某些promise,那么使用不可避免的Deferreds编写自己的函数应该是最后一个选项 . 考虑切换到功能更强大的库,和/或针对当前库提交错误 . 它的维护者应该能够从现有函数派生组合,为您实现新的辅助函数和/或帮助识别需要处理的边缘情况 .

相关问题