问题:什么是显式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() */ |     });
}                                        | }

有人告诉我,这分别称为" 延迟反模式"或" Promise构造函数反模式",此代码和为什么将其称为反模式

标签:javascript,promise,q,bluebird,es6-promise

回答1:

递延反模式(现在是显式构造)反模式) Esailija 创造,是一个常见的反模式人士,他们对诺言做出了新的尝试,我当我第一次使用诺言时,我自己做了。上面的代码的问题是无法利用承诺链这一事实。

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

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

承诺的全部目的在于使异步代码更具可读性,并且在不隐藏事实的情况下像同步代码一样工作。承诺表示对一次操作值的抽象,它们抽象出一种编程语言中的语句或表达式的概念。

仅当您时,才应使用延迟对象。将API转换为Promise 并不能自动执行,或者您正在编写以这种方式表示的聚合函数时。

报价Esailija:

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

回答2:

怎么了?

但是该模式有效!

幸运的你。不幸的是,可能不会,因为您可能忘记了一些极端情况。在我所见过的事件中,有一半以上是作者忘记照顾错误处理程序的:

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()进行链接更加安全。

但是我已经处理了一切!

真的吗?好。但是,这将非常详细和丰富,尤其是如果您使用支持其他功能(例如取消或消息传递)的Promise库。也许将来会,或者您想将图书馆换成更好的图书馆?您将不想为此重写代码。

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

如何避免呢?

因此,只要您发现自己手动创建PromiseDeferred,并且已经涉及到现有的诺言,请首先检查库API 。 Deferred反模式通常由将promise(仅)视为观察者模式的人使用,但是承诺是 more 比回调:它们应该是可组合的。每个体面的图书馆都有许多易于使用的功能,以各种可行的方式来构成承诺,可以处理所有您不想处理的低级内容。

如果您发现有需要以现有助手功能不支持的新方式撰写某些Promise,那么使用不可避免的Deferreds编写自己的函数应该是您的最后选择。考虑切换到功能更强大的库,和/或针对当前库提出错误。它的维护者应该能够从现有功能中获取组成,为您实现新的帮助器功能和/或帮助确定需要处理的边缘情况。

回到顶部