使用Q / promise和callback

我在nodejs中使用Q库,过去没有太多的承诺,但我有半复杂的逻辑,需要大量的嵌套,并认为Q将是一个很好的解决scheme,但是我发现它似乎几乎就像“回拨地狱”一样。

基本上我已经说了5种方法,所有这些都需要上一个或之前的数据。 这是一个例子:

我们从一些二进制数据开始,基于二进制生成一个sha1哈希。

var data = { hash : "XXX" , binary: '' } 

首先我们要看看我们是否已经有了这个,使用这个方法:

findItemByHash(hash)

如果我们没有它,我们需要保存它,使用:

saveItem(hash)

现在我们需要把这个关联到一个用户,而不仅仅是保存的结果。 现在有一个更大的层次结构,所以我们需要首先做到这一点:

getItemHierarchy(item_id) ,我们使用从我们以前的saveItem返回的item_id

现在,我们可以将这些结果“复制”给用户:

saveUserHierarchy(hierarchy)

现在我们已经完成了,但是,这是假设该项目还不存在。 所以我们需要处理这个项目确实存在的情况。 这将是:

我们需要检查用户是否有这样的:

getUserItemByItemId(item_id) – item_id从findItemByHash返回

如果存在,我们就完成了。

如果没有:

getItemHierarchy(item_id)

然后

saveUserHierarchy(hierarchy)

好的,现在我们有callback做这些检查,这很好。 但是,我们需要在每种情况下处理错误。 这也没关系,只是增加了混乱。 真的,如果stream程的任何部分抛出错误或拒绝,那么它可以停下来,只是在一个地方处理它。

现在用Q,我们可以做这样的事情:

 findItemByHash(hash).then(function(res) { if (!res) { return saveItem(hash).then(function(item) { return getItemHierarchy(item.id).then(function(hierarchy) { return saveUserHierarchy(hierarchy); }); }) } else { return getUserItemByItemId(res.id).then(function(user_item) { if (user_item) { return user_item; } return getItemHierarchy(res.id).then(function(hierarchy) { return saveUserHierarchy(hierarchy); }); }); } }) //I think this will only handle the reject for findItemByHash? .fail(function(err) { console.log(err); }) .done(); 

所以,我想我的问题是这样的。 在Q中有更好的方法来处理这个问题吗?

谢谢!

我喜欢承诺的原因之一是处理错误是多么容易。 在你的情况下,如果这些承诺中的任何一个都失败了,它将会被你定义的故障条款所捕获。 如果你想现场处理它们你可以指定更多的fail子句,但这不是必需的。

作为一个简单的例子,有时我想处理错误,并返回其他的东西,而不是传递错误。 我会做这样的事情:

 function awesomeFunction() { var fooPromise = getFoo().then(function() { return 'foo'; }).fail(function(reason) { // handle the error HERE, return the string 'bar' return 'bar'; }); return fooPromise; } awesomeFunction().then(function(result) { // `result` will either be "foo" or "bar" depending on if the `getFoo()` // call was successful or not inside of `awesomeFunction()` }) .fail(function(reason) { // This will never be called even if the `getFoo()` function fails // because we've handled it above. }); 

现在,关于退出“返回地狱”的问题 – 只要下一个函数不需要关于前一个函数的信息,就可以链接.then子句而不是嵌套它们:

 doThis().then(function(foo) { return thenThis(foo.id).then(function(bar) { // `thenThat()` doesn't need to know anything about the variable // `foo` - it only cares about `bar` meaning we can unnest it. return thenThat(bar.id); }); }); // same as the above doThis().then(function(foo) { return thenThis(foo.id); }).then(function(bar) { return thenThat(bar.id); }); 

为了进一步减less它,使function组合重复承诺组合,我们留下:

 function getItemHierarchyAndSave(item) { return getItemHierarchy(item.id).then(function(hierarchy) { return saveUserHierarchy(hierarchy); }); } findItemByHash(hash).then(function(resItem) { if (!resItem) { return saveItem(hash).then(function(savedItem) { return getItemHierarchyAndSave(savedItem); }); } return getUserItemByItemId(resItem.id).then(function(userItem) { return userItem || getItemHierarchyAndSave(resItem); }); }) .fail(function(err) { console.log(err); }) .done(); 

免责声明:我不使用Q承诺, when承诺主要是为了它附带的额外的好处when ,我倾向于承诺 ,但原则是相同的。