这是“延迟反模式”吗?
Posted
技术标签:
【中文标题】这是“延迟反模式”吗?【英文标题】:Is this a "Deferred Antipattern"? 【发布时间】:2015-08-25 08:14:24 【问题描述】:我发现很难理解“延迟反模式”。我想我原则上理解它,但我还没有看到一个超级简单的例子来说明什么是服务,有不同的承诺和反模式,所以我想我会尝试自己做,但看看我不是超级了解它,我会先得到一些澄清。
我在工厂(SomeFactory)有以下内容:
//url = 'data.json';
return
getData: function()
var deferred = $q.defer();
$http.get(destinationFactory.url)
.then(function (response)
if (typeof response.data === 'object')
deferred.resolve(response.data);
else
return deferred.reject(response.data);
)
.catch(function (error)
deferred.reject(error);
);
return deferred.promise;
我检查它的对象的原因只是为了在$http.get()
上添加一个简单的验证层
下面,在我的指令中:
this.var = SomeFactory.getData()
.then(function(response)
//some variable = response;
)
.catch(function(response)
//Do error handling here
);
现在据我了解,这是一种反模式。因为最初的延迟承诺会捕获错误并简单地吞下它。它不会返回错误,因此当调用此“getData”方法时,我会再次捕获错误。
如果这不是反模式,那么有人可以解释为什么两者都需要某种“回调”吗?当我第一次开始编写这个工厂/指令时,我预计必须在某个地方做一个延迟承诺,但我没有预料到双方都必须.catch()
(也就是我想我可以让工厂返回响应或如果我做了SomeFactory.getData()
,则会出现错误
【问题讨论】:
【参考方案1】:这是“延迟反模式”吗?
是的,是的。 “延迟反模式”在创建新的冗余延迟对象以从承诺链内部解决时发生。在您的情况下,您使用 $q 来返回隐含返回承诺的承诺。你已经有一个 Promise 对象($http service
本身返回一个promise
),所以你只需要返回它!
这是一个超级简单的示例,展示了一个带有延迟承诺和一个带有反模式的服务的样子,
这是反模式
app.factory("SomeFactory",['$http','$q']) return getData: function() var deferred = $q.defer(); $http.get(destinationFactory.url) .then(function (response) deferred.resolve(response.data); ) .catch(function (error) deferred.reject(error); ); return deferred.promise; ])
这是你应该做的
app.factory("SomeFactory",['$http'])
return
getData: function()
//$http itself returns a promise
return $http.get(destinationFactory.url);
虽然它们都以相同的方式消耗。
this.var = SomeFactory.getData()
.then(function(response)
//some variable = response;
,function(response)
//Do error handling here
);
这两个例子都没有问题(至少在语法上)..但第一个是多余的..不需要!
希望对你有帮助:)
【讨论】:
您好 NLN,感谢您的回复。因此,在您的示例中,是否包含typeof
验证,或者在从工厂检索后在控制器中完成?
嗨阿列斯基。您可以在.success()
函数中执行typeof
验证:)
我在未登录的情况下进行了编辑,现在它已被锁定。基本上, .success 和 .error 已被弃用。您现在可以使用 .then。
@SenHeng:你的编辑看起来不错(而且很有必要,有点),谢谢 :)
我不认为第一个是多余的并且不需要。可能您想在工厂中操作数据并在那里保存其他控制器共享的值...【参考方案2】:
我会说它是 classic 延迟反模式,因为您正在创建不必要的延迟对象。但是,您正在为链添加一些价值(通过您的验证)。通常,在 IMO 中,当创建延迟对象的好处很少或没有好处时,反模式尤其糟糕。
因此,代码可以简单得多。
$q
promise 有一个小记录功能,即自动将任何返回的内容包装在一个 promise 中(使用 $q.when
)。在大多数情况下,这意味着您不必手动创建延迟:
var deferred = $q.defer();
但是,这就是文档演示如何将 Promise 与 $q
一起使用的方式。
因此,您可以将代码更改为:
return
getData: function()
return $http.get(destinationFactory.url)
.then(function (response)
if (typeof response.data === 'object')
return response.data;
else
throw new Error('Error message here');
);
// no need to catch and just re-throw
);
【讨论】:
好吧,因为添加了我的光验证,我应该离开“回调”-y 然后部分,因为我在返回它之前对它做一些事情?在使用 Promise 之前在 Promise 中做一些工作有多常见?我更喜欢 NLN 的回答,但他不得不放弃我的验证...... 从 Promise 链中读取数据,做一些逻辑然后返回数据进行进一步处理是很常见的。这就是使它成为 chain 的原因:)。最后,您到达终点并将数据绑定到$scope
或任何地方。
所以这里的问题真的是让$q
不必要地参与吗?
是的,你可以想象你有一个多层的承诺链。为链中的每个链接创建一个deferred
会很麻烦,而且没有必要。【参考方案3】:
使用$q constructor 是一种延迟反模式
反模式
vm.download = function() var url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"; return $q(function(resolve, reject) var req = method: 'POST', url: url, responseType: 'arraybuffer' ; $http(req).then(function(response) resolve(response.data); , function(error) reject(error); ); );
正确
vm.download = function()
var url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf";
var req =
method: 'POST',
url: url,
responseType: 'arraybuffer'
;
return $http(req).then(function(response)
return response.data;
);
$http 服务已经返回了一个承诺。使用$q constructor 是不必要的并且容易出错。
【讨论】:
以上是关于这是“延迟反模式”吗?的主要内容,如果未能解决你的问题,请参考以下文章