【问题标题】:Difference between callback hell and nested promises回调地狱和嵌套承诺之间的区别
【发布时间】:2015-06-06 03:41:59
【问题描述】:

我最近开始使用 NodeJS 和 MongoDB(使用 Monk)。这是我遇到“回调地狱”一词的时候。在我的代码中,我正在做同样的事情。举个例子-

DBCall(d1, function(e, docs){
 if(docs.length!=0)
  DBCall(d2, function(e, docs1){
   if(docs1.length!=0)
    DBCall(d3, function(e, docs2){
      //doing something with docs,docs1,docs2
    }) 
  }) 
}) 

这是我开始阅读“承诺”的时候,我偶然发现了这篇文章 - https://strongloop.com/strongblog/promises-in-node-js-with-q-an-alternative-to-callbacks/

由于我在第三个回调中同时需要 docs 和 docs1,所以我使用了嵌套的 Promise。

DBCall(d1)
.then(function(docs){
  if(docs.length!=0)
   return DBCall(d2)
   .then(function(docs1){
     if(docs1.length!=0)
      return DBCall(d3)
      .then(function(docs2){
        //doing something with docs,docs1,docs2
      })
    })
  })

从上面的代码 sn-p 我有以下问题(/疑问):

  1. 除了使代码更具可读性之外,Promise 是否具有性能优势?
  2. 嵌套承诺和回调地狱看起来与我相似。真的有区别吗?

我不熟悉这种承诺的概念。任何帮助表示赞赏。

【问题讨论】:

  • 从技术上讲,您的嵌套承诺仍在使用回调,从而再次创建“回调地狱”。这次有更多代码。
  • 那么,如果我使用 Promise 并且如果我想使用 docs,docs1,docs2 ,有没有办法避免回调地狱?
  • @User - 看看我更新的答案中的一些链接。

标签: javascript node.js callback


【解决方案1】:

基本上,Promises 的目的是允许功能组合和错误处理,以一种同步读取的方式。 Promise 允许您以线性(可能是错误的术语)或同步方式阅读代码。

这是一个广泛的问题,但请查看这些建议的链接。

https://promise-nuggets.github.io/
https://blog.domenic.me/youre-missing-the-point-of-promises/

also this link

编辑: 阅读您的更新后,您实际上要求的是加入承诺(我认为)

这个SO Post 提供了一些很好的信息。一些更好的库具有实用功能来帮助解决这个问题。

例如,如果使用 bluebird,请查看 join function

【讨论】:

  • 您提供的链接真的很有帮助。我的情况类似于“加入函数”,只是我只想在返回的结果(在我的情况下为 docs/docs1)不为空时进行下一次调用。
  • @User 很酷,很高兴它有帮助。如果您需要以回调样式(您的第一个示例)运行类似的东西,请尝试查看 async module 。您可以执行基本相同的操作,但使用常规回调方式。
【解决方案2】:

除了让代码更具可读性之外,Promise 是否还有性能优势?

可能不会。

嵌套承诺和回调地狱看起来和我很相似。真的有区别吗?

Promise 不会自动阻止回调地狱。但是因为它们比“简单”的回调更灵活,它们可以以不同的方式组合,从而更容易避免回调地狱。


由于我在第三个回调中同时需要 docs 和 docs1,所以我使用了嵌套的 Promise。

有时嵌套的 Promise 是不可避免的。但是,如果它们不必按顺序执行,则无需嵌套它们。您可以并行执行它们:

Promise.all([
 DBCall(d1),
 DBCall(d2),
 DBCall(d3)
]).then(function(docs) {
  // docs is an array: [docs, docs1, docs2]
});

【讨论】:

  • 这是一个很好的解决方案。但我的情况稍微复杂一点。我编辑了问题以便更好地理解。