我在nodejs中使用Q库并且过去没有对promises工作太多,但是我有半复杂的逻辑需要大量的嵌套,并且认为Q是一个很好的解决方案,但是我发现它似乎与“回调地狱”几乎相同。
基本上我说有5种方法,都需要前一种或前一种方法的数据。这是一个例子:
我们从一些二进制数据开始,这些数据具有基于二进制生成的sha1哈希。
var data = {
hash : "XXX"
, binary: ''
}
首先,我们希望看看我们是否已经使用此方法:
findItemByHash(hash)
如果我们没有,我们需要保存它,使用:
saveItem(hash)
现在我们需要将其与用户相关联,而不仅仅是保存的结果。现在我们关联的层次结构要大得多,所以我们首先需要做到这一点:
getItemHierarchy(item_id)
,我们使用之前item_id
saveItem
现在,我们可以将这些结果“复制”给用户:
saveUserHierarchy(hierarchy)
现在我们已经完成了,但是,假设该项目尚未存在。所以我们需要处理项目确实存在的情况。这将是:
我们需要检查用户是否有这个:
getUserItemByItemId(item_id)
- item_id已从findItemByHash
如果存在,我们就完成了。
如果没有:
getItemHierarchy(item_id)
然后
saveUserHierarchy(hierarchy)
好的,现在我们有回调来做这些检查,这很好。但是我们需要在整个过程中处理每种情况下的错误。这也很好,只是增加了混乱。实际上,如果流的任何部分抛出错误或拒绝,那么它可以停止并在一个地方处理它。
现在有了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中有没有更好的方法来处理这个问题?
谢谢!
答案 0 :(得分:4)
我喜欢承诺的原因之一是处理错误是多么容易。在您的情况下,如果其中任何一个promise失败,它将被您定义的fail子句捕获。如果您想在现场处理 ,可以指定更多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);
});
为了进一步减少它,制作组合重复承诺组合的函数,我们留下:
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
promises,但原则是相同的。