在承诺中包装现有API的回调是否有好处,以避免"回调地狱"?

时间:2016-01-04 22:09:09

标签: javascript node.js promise

所以在这一点上,承诺似乎有更多的牵引力,因为"最佳实践"比回调,但许多现有的库仍然使用回调。

所以给定一个已经实现了这样的回调模式的库:

library.connect(function(err) {
  library.someQuery({}).exec(function(err, result) {
    // some code
    library.someQuery(result).exec(function(err2, result2) {
      // some code
    })
  })
})

将这些回调包装在promises中是否有益于避免嵌套?

new Promise((resolve, reject) => {
  library.connect(function(err) {
    if (err) reject(err)
    else resolve()
  }
}).then(() => {
  return new Promise((resolve, reject) => {
    library.someQuery({}).exec((err, result) => {
      if (err) reject(err)
      else resolve(result)
    }
  })
}).then((result) => {
  return new Promise((resolve, reject) => {
    library.someQuery(result).exec(function(err2, result2) {
      if (err) reject(err2)
      else resolve(result2)
    }
}).then((result) => {
  // some code
}).catch((err) => // handle error)

没有嵌套它会更好,但它更冗长。此外,我不确定这会带来多少额外的好处。也许更好的错误处理?

2 个答案:

答案 0 :(得分:2)

在您的第一个代码段中,您有多个位置来处理错误,而对于承诺,您只有一个。

我认为你做了一些很好的观察,也补充说使用promises会对性能产生轻微的开销。但是,如果您可以使用重复的代码,那么您可能会使用它们获得更容易调试的代码。

您还可以创建一个小函数来抽象出承诺,但请记住,这会增加一些开销:

// Non tested code, but hopes it shows a point
function make_promisable(context, method) {
  return new Promise((resolve, reject) => {
    context[method]((err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
};
// Note: The below actually seems to hide the logic in the code,
//   is this any good, or harder to read/debug?
make_promisable(library, 'connect').then(() => {
  return make_promisable(library.someQuery({}), 'exec');
}).then((result) => {
  return make_promisable(library.someQuery(result), 'exec');
}).then((result) => {
  // some code
}).catch((err) => // handle error)

答案 1 :(得分:1)

这主要是意见,但是:

  • 如果您不止一次这样做,可能值得为公开基于Promise的API的库编写外观:

    import library from 'library';
    
    export default {
        connect() {
            return new Promise((resolve, reject) => {
              library.connect(function(err) {
                if (err) reject(err)
                else resolve()
              }
            }
        }
        // etc
    }
    
  • 回调地狱/嵌套是一个实现问题,不是回调的基本问题,通常可以通过分解函数而不是嵌套来改进。像async这样的图书馆使回调像Promises一样易读,或者更多。

  • 承诺的一个优点(?)是您可以使用async/await语法(假设Babel进行转换)。在实践中,我发现这种语法很棘手,但有些人真的很喜欢它。