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

我正在编写的代码看起来像这样:

使用Promise构造函数:

function getStuffDone(param) {
    return new Promise(function(resolve, reject) {
        myPromiseFn(param+1)
            .then(function(val) { resolve(val); }) // or .then(resolve)
            .catch(function(err) { reject(err); }); // or .catch(reject)
    });
} 

使用Q或延期:

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

有人告诉我这叫做“ 延迟反模式 ”或“ Promise构造函数反模式 ”,这段代码有什么不好,为什么这叫做反模式?


由Esailija创造的延期反模式(现在是明确的建造反模式)是一种常见的反模式人,他们是承诺的新人,我在第一次使用承诺时自己做出了自己的承诺。 上述代码的问题在于未能利用承诺链条这一事实。

承诺可以与.then链接.then然后您可以直接返回承诺。 您在getStuffDone代码可以被重写为:

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

承诺就是让异步代码更具可读性并像同步代码一样行事而不会隐藏这个事实。 Promises代表对一次操作值的抽象,它们用编程语言抽象出语句或表达的概念。

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

引用Esailija:

这是最常见的反模式。 当你没有真正理解承诺并将它们看作是荣耀的事件发射器或回调实用程序时,很容易陷入这种情况。 让我们回顾一下:promises是关于使异步代码保留大部分同步代码的丢失属性,例如平面缩进和一个异常通道。


它出什么问题了?

但模式起作用!

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

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;
 })

延迟反模式不仅麻烦,而且容易出错 。 使用.then()进行链接更安全。

但我已经处理了一切!

真? 好。 但是,这将非常详细和丰富,特别是如果您使用支持其他功能(如取消或消息传递)的承诺库。 或者也许它会在未来,或者你想换一个更好的图书馆? 你不会想重写你的代码。

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

我如何避免它?

因此,无论何时您发现自己手动创建PromiseDeferred并涉及已有的promise, 请首先检查库API 。 延迟反模式经常被那些只看到承诺作为观察者模式的人应用 - 但承诺不仅仅是回调:它们应该是可组合的。 每个体面的图书馆都有许多易于使用的功能,用于以可想象的方式组织承诺,照顾所有不想处理的低层次内容。

如果您发现需要以现有的帮助函数不支持的新方式编写一些承诺,那么使用不可避免的延期编写自己的函数应该是您的最后选择。 考虑切换到更多功能的库,和/或提交一个针对当前库的错误。 它的维护者应该能够从现有函数派生出合成,为你实现一个新的帮助函数和/或帮助识别需要处理的边缘案例。

链接地址: http://www.djcxy.com/p/9443.html

上一篇: What is the explicit promise construction antipattern and how do I avoid it?

下一篇: Js Deferred/Promise/Future compared to functional languages like Scala