提问者:小点点

什么是显式promise构造反模式,我如何避免它?


我写的代码看起来像:

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() */ |     });
}                                        | }

有人告诉我这分别被称为“延迟反模式”或“codePromise/code>constructor反模式”,这段代码有什么不好,为什么被称为反模式?


共2个答案

匿名用户

Esailija提出的递延反模式(现在的显式构造反模式)是一种常见的反模式,对于那些不熟悉诺言的人来说,我第一次使用诺言的时候就自己做了。上述代码的问题在于未能利用承诺链的事实。

承诺可以与链接,您可以直接返回承诺。中的代码可以重写为:

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

承诺都是关于使异步代码更具可读性和行为类似于同步代码而不隐藏这一事实。承诺表示对一次运算值的抽象,它们抽象了编程语言中的语句或表达式的概念。

只有在将API转换为承诺而不能自动进行转换时,或者在编写更容易以这种方式表达的聚合函数时,才应该使用延迟对象。

引用Esailija的话:

这是最常见的反模式。当你不真正理解承诺,把它们看作是荣耀的事件发射器或回调效用时,很容易陷入这种境地。让我们重述一下:承诺是关于使异步代码保留同步代码丢失的大部分属性,如平面缩进和一个异常通道。

匿名用户

但这模式行得通!

你太幸运了。不幸的是,它可能不是,因为你可能忘记了一些边缘案例。在我所见过的超过一半的情况中,作者忘记了处理错误处理程序:

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

如果另一个承诺被拒绝,这将在未被注意的情况下发生,而不是传播到新的承诺(在那里处理它)--新的承诺将永远停留在未决状态,这可能导致泄露。

在回调代码导致错误的情况下,也会发生同样的情况--例如没有并且抛出了异常。这将得不到处理,新的承诺也将悬而未决。

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

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

延迟反模式不仅繁琐,而且容易出错。使用进行链接要安全得多。

但我已经处理了一切!

null

Libraries的方法(codethen/code>)不仅本地支持所有特性,它们还可能进行了某些优化。使用它们可能会使您的代码更快,或者至少允许在库的未来修订中进行优化。

因此,每当您发现自己手动创建了并且涉及到已经存在的承诺时,请首先检查库API。延迟反模式通常被那些将承诺(仅)视为观察者模式的人应用--但是承诺不仅仅是回调:它们应该是可组合的。每个像样的库都有许多易于使用的函数,用于以各种可以想到的方式组合承诺,处理所有你不想处理的低级事务。

如果您发现需要以一种新的方式来编写一些承诺,而现有的helper函数不支持这种方式,那么编写带有不可避免的延迟的自己的函数应该是您的最后选择。考虑切换到一个更有特色的库,和/或针对当前库提交一个bug。它的维护者应该能够从现有功能派生组合,为您实现一个新的帮助器功能和/或帮助识别需要处理的边缘情况。