什么是明确的承诺build设反模式,我如何避免它?
我正在编写的代码看起来像这样:
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() */ | }); } | }
有人告诉我这叫做“ 延迟反模式 ”或“ Promise
构造函数反模式 ”,这段代码有什么不好,为什么这叫做反模式 ?
Esailija创造的延期反模式(现在是明确的build造反模式)是一种常见的反模式的人,他们是承诺的新人,我在第一次使用诺言时就自己做了。 上述代码的问题是未能利用承诺链条的事实。
承诺可以和。然后你可以直接返回承诺。 您在getStuffDone
代码可以被重写为:
function getStuffDone(param){ return myPromiseFn(param+1); // much nicer, right? }
承诺就是让asynchronous代码更具可读性,并像同步代码一样行事,而不会隐藏这个事实。 Promise代表对一次操作的值的抽象,它们以一种编程语言来抽象语句或expression的概念。
在将API转换为承诺时,只应使用延迟对象,并且不能自动执行,或者在编写更容易expression的聚合函数时使用延迟对象。
引用Esailija:
这是最常见的反模式。 当你没有真正理解承诺,并把它们看作是美化的事件发射器或callback工具时,很容易陷入这种情况。 让我们回顾一下:承诺是使asynchronous代码保留大部分同步代码的丢失属性,如平面缩进和一个exception通道。
它出什么问题了?
但模式的作品!
幸运的你。 不幸的是,它可能不会,因为你可能会忘记一些边缘情况。 在我看到的一半以上的事件中,作者忘记了照顾error handling程序:
return new Promise(function(resolve) { getOtherPromise().then(function(result) { resolve(result.property.example); }); })
如果另一个承诺被拒绝,这种情况将会被忽视,而不是被传播到新的承诺(它将得到处理),而新的承诺会一直处于待决状态,从而导致泄漏。
同样的事情发生在你的callback代码导致错误的情况下 – 例如,当result
没有property
和抛出exception时。 这将不受处理,并留下新的承诺未解决。
相反,使用.then()
会自动处理这两种情况,并在发生错误时拒绝新的承诺:
return getOtherPromise().then(function(result) { return result.property.example; })
延迟的反模式不仅麻烦,而且容易出错 。 使用.then()
进行链接更安全。
但我已经处理了一切!
真? 好。 但是,这将是非常详细和丰富的,特别是如果您使用承诺库,支持其他function,如取消或消息传递。 或者也许会在未来,或者你想换一个更好的图书馆? 你不会想重写你的代码。
图书馆的方法( then
)不仅本身支持所有的function,而且还可能有一定的优化。 使用它们可能会使你的代码更快,或者至less可以通过库的未来修订来优化。
我如何避免它?
因此,无论何时您手动创buildPromise
或Deferred
并且已经存在Promise
,都要先检查库API 。 延迟反模式通常被看作是观察者模式的人所应用,但是承诺不仅仅是callback :它们应该是可组合的。 每一个体面的图书馆都有许多易于使用的function,用于以可想象的方式构成承诺,照顾所有你不想处理的低层次的东西。
如果您发现需要以现有的帮助函数不支持的新方式撰写某些承诺,那么使用不可避免的延期编写自己的函数应该是您的最后select。 考虑切换到更多function的库,和/或文件对当前库的错误。 它的维护者应该能够从现有的函数中派生出合成,为你实现一个新的帮助函数和/或帮助识别需要处理的边界情况。