【发布时间】:2015-04-29 22:42:49
【问题描述】:
短篇小说:
谈到 Promises/A+,拒绝承诺的正确方法是什么 - 抛出错误?但是如果我错过了
catch- 我的整个应用程序都会崩溃!如何使用
promisify,它有什么好处(也许你需要阅读更长的版本)?.then(success, fail)真的是anti-pattern,我应该一直使用.then(success).catch(error)吗?
加长版,描述为现实生活中的问题(希望有人阅读):
我有一个使用Bluebird(A+ Promise 实现库)的库,用于从数据库中获取数据(谈论Sequelize)。每个查询都会返回一个结果,但有时它是空的(试图选择一些东西,但没有任何结果)。承诺进入result 函数,因为没有错误的理由(没有结果不是错误)。示例:
Entity.find(1).then(function(result) {
// always ending here, despite result is {}
}).catch(function(error) {
// never ends here
});
我想包装它并检查结果是否为空(无法在我的代码中到处检查)。我这样做了:
function findFirst() {
return Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
return result; // will invoke the success function
} else {
// I WANT TO INVOKE THE ERROR, HOW?! :)
}
}).catch(function(error) {
// never ends here
});
}
findFirst().then(function(result) {
// I HAVE a result
}).catch(function(error) {
// ERROR function - there's either sql error OR there is no result!
});
如果你还在我身边 - 我希望你能明白发生了什么。我想以某种方式启动错误功能(“错误功能”在哪里)。问题是 - 我不知道怎么做。我试过这些东西:
this.reject('reason'); // doesn't work, this is not a promise, Sequelize related
return new Error('reason'); // calls success function, with error argument
return false; // calls success function with false argument
throw new Error('reason'); // works, but if .catch is missing => BLOW!
正如您在我的 cmets 中看到的(并且根据规范),抛出错误效果很好。但是,有一个很大的 但是 - 如果我错过了 .catch 声明,我的整个应用程序就会崩溃。
为什么我不想要这个?假设我想在我的数据库中增加一个计数器。我不关心结果——我只是发出 HTTP 请求。所以我可以调用incrementInDB(),它可以返回结果(即使是出于测试原因),所以如果它失败了会有throw new Error。但由于我不关心响应,有时我不会添加 .catch 语句,对吗?但是现在 - 如果我不这样做(故意或由于错误) - 我最终会导致您的节点应用程序关闭。
我觉得这不是很好。有没有更好的方法来解决它,或者我只需要处理它?
我的一个朋友帮助了我,我使用了一个新的承诺来解决问题,如下所示:
function findFirst() {
var deferred = new Promise.pending(); // doesnt' matter if it's Bluebird or Q, just defer
Entity.find(1).then(function(result) {
if (result) { // add proper checks if needed
deferred.resolve(result);
} else {
deferred.reject('no result');
}
}).catch(function(error) {
deferred.reject('mysql error');
);
return deferred.promise; // return a promise, no matter of framework
}
像魅力一样工作! 但是我进入了这个:Promise Anti Patterns - 由 Bluebird 的创建者 Petka Antonov 撰写的 wiki 文章(A+ 实现)。明确表示这是错误。
所以我的第二个问题是 - 是这样吗?如果是 - 为什么?最好的方法是什么?
非常感谢您阅读本文,我希望有人能花时间为我解答 :) 我应该补充一点,我不想过多依赖框架,所以 Sequelize 和 Bluebird 只是事情我最终与之合作。我的问题是 Promises 作为一个全局的,而不是这个特定的框架。
【问题讨论】:
-
致
But, there's a big but - if I miss the .catch statement, my whole app blows up.这不就是例外吗?您应该始终处理异常,即使您不关心失败,您也应该在代码中通过添加.catch和您不关心的注释来明确这一点。想象一下,稍后您将再次查看您的代码并发现有一个未处理的异常,但您不记得为什么它未处理,那么您将花费大量时间来确定原因。 -
这是关于生产力,与多个开发人员合作,而不是最后 - 可靠性。任何开发人员只写
incrementInDB();比浏览代码更容易,读到这是一个会引发错误的承诺,所以你必须抓住它。正如我所说 - 我不想要例外 - 我只是想不出另一种方法来做到这一点而不炸毁我的整个应用程序:) -
我认为 t.niese 的评论应该是一个答案。是的,任何开发人员编写一行代码可能比编写正确代码更容易,但这不是借口。我经常看到来自没有经验的开发人员的代码,其中一些 API 抛出的异常被默默地吞下并转换为返回 null 等。一些开发人员似乎对异常有某种基本的恐惧。正确使用 catch() 和 done() 我真的没有看到任何问题。此外,如果需要,您总是可以编写自己的未捕获异常处理程序?
-
感谢您的回复。我只是觉得处于两个极端很奇怪——要么不使用异常,要么总是使用它们。在编程中,单个请求中有更多的情况——它可以返回多种类型的响应(甚至是错误类型)。我的意思是 - 我不能总是祈祷团队的开发人员都没有忘记使用
.catch,因此我们的产品生产中不会完全崩溃..可靠性最重要。 -
我不明白如何拒绝承诺或使用传达所有内容的值解决问题而不是抛出异常是一种反模式。 Antonov 似乎只是在争论应该使用
.catch()而不是.then()中的fail处理程序。这对我来说似乎纯粹是一个风格问题,他只是在表达他的意见。除了将 try/catch 用于同步代码的粗略类比之外,他没有为该观点提供任何令人信服的理由。但是,在同步代码中也有数百种其他方式返回错误。
标签: javascript node.js promise bluebird