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

2022-08-29 22:40:59

我正在编写代码,该代码可以执行如下所示的内容:

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

有人告诉我,这分别被称为“延迟反模式”或“承诺构造函数反模式”,这个代码有什么不好的,为什么这被称为反模式


答案 1

Esailija创造的延迟反模式(现在是显式构建反模式)是一种常见的反模式人,他们是新承诺的人,当我第一次使用承诺时,我自己已经做到了。上述代码的问题在于未能利用承诺链的事实。

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

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

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

仅当将 API 转换为 promise 且无法自动执行此操作时,或者当您编写以这种方式更易于表达的聚合函数时,才应使用延迟对象。

引用Esailija的话:

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


答案 2

这是怎么回事?

但是这个模式有效!

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

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

如果另一个承诺被拒绝,这将在不被注意的情况下发生,而不是传播到新承诺(它将被处理的地方) - 并且新承诺将永远处于待定状态,这可能会引起泄漏。

在回调代码导致错误的情况下也会发生同样的事情 - 例如,当没有 a 并且引发异常时。这将得不到处理,使新的承诺得不到解决。resultproperty

相比之下,using 确实会自动处理这两种情况,并在发生错误时拒绝新承诺:.then()

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

延迟的反模式不仅繁琐,而且容易出错。用于链接更安全。.then()

但是我已经处理好了一切!

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

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

我该如何避免?

因此,每当您发现自己手动创建或并且已经存在的承诺涉及时,请先检查库API。延迟反模式通常由那些将承诺[仅]视为观察者模式的人使用- 但承诺不仅仅是回调:它们应该是可组合的。每个像样的库都有许多易于使用的功能,用于以各种可思议的方式组合承诺,处理所有您不想处理的低级内容。PromiseDeferred

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