node.js - 使用 Q/promises 与回调

标签 node.js q

我正在使用 Q nodejs 中的库并且过去没有太多地使用 promises,但是我有需要大量嵌套的半复杂逻辑并且认为 Q 将是一个很好的解决方案,但是我发现它似乎与只是“回调 hell ”。

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

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

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

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

findItemByHash(哈希)

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

保存项目(哈希)

现在我们需要将其关联到用户,而不仅仅是保存的结果。现在我们关联了一个更大的层次结构,所以我们需要首先得到它,做:

getItemHierarchy(item_id),我们使用从之前的 saveItem

返回的 item_id

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

saveUserHierarchy(层次结构)

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

我们需要检查用户是否可能有这个:

getUserItemByItemId(item_id) - item_id 是从 findItemByHash

返回的

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

如果没有:

getItemHierarchy(item_id)

然后

saveUserHierarchy(层次结构)

好的,现在我们有执行这些检查的回调,这很好。但是我们需要一路处理每种情况下的错误。这也很好,只是增加了困惑。实际上,如果流程的任何部分抛出错误或拒绝,那么它可以停止并在一个地方处理它。

现在有了 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 中有更好的方法来处理这个问题吗?

谢谢!

最佳答案

我喜欢 promises 的原因之一是处理错误非常容易。在您的情况下,如果这些 promise 中的任何一个失败,它将在您定义的失败子句中被捕获。如果您想当场处理它们,您可以指定更多的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.
});

现在关于您关于摆脱“返回 hell ”的问题 - 只要下一个函数不需要有关前一个函数的信息,您就可以链接 .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);
});

为了进一步减少它,创建组合重复 promise 组合的函数,我们剩下:

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 promise ,我更喜欢 when promises主要是因为它附带的额外好处,但原理是相同的。

关于node.js - 使用 Q/promises 与回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20430562/

相关文章:

javascript - 想要根据一系列其他 promise 完成来返回 promise

node.js - 将 Q 迁移到 BlueBird(或 Vow)

javascript - 如何使用 node.js Q 在链执行期间插入 promise ?

javascript - 设置后如何将 Express.js 用于新的 Web 应用程序?

javascript - 从事件更新 react 变量

angularjs - 连接到 Node REST api 的应用程序被客户防火墙阻止

mysql - Node mysql批量插入带有express数组参数

javascript - 如何将 Array.forEach 转换为与 Q.js 异步?

javascript - 将参数传递给 angularjs $q 中 promise 的成功回调

javascript - 如何控制 WebRTC 视频通话中的带宽?