使用promises时的逻辑流程

时间:2016-08-12 15:05:40

标签: javascript asynchronous callback promise

人为的例子

假设我们需要在某些Node应用程序中为Foo构建BarUser。我们应该实现constructFooForUser函数,该函数必须使用

调用某些callback函数
  • Error
  • 空错误,已创建的Foo和已创建的Bar

为此,我们必须使用一些数据库函数来获取/创建我们的对象,返回一个Promise。

var constructFooForUser = function(userId, data, callback) {

  db.users.find(userId)
    .then(function(user) {
      if (!user) { return callback(new Error('user not found')); }

      db.foos.create(user, data)
        .then(function(foo) {

          db.bars.create(user, foo, data)
            .then(function(bar) {

              callback(null, foo, bar);

            })
            .catch(function(err) {
              callback(err);
            });

        })
        .catch(function(err) {
          callback(err);
        });

    })
    .catch(function(err) {
      callback(err);
    });

};

这是构建此类基于承诺的代码的正确方法吗?

我看过Promise代码的示例,看起来像是

doSomething()
  .then(doSomethingElse)
  .then(doYetAnotherThing)
  .then(doLastThing)
  .catch(handleError);

但我认为这不适用于这种情况,因为我需要同时使用user,foo和bar,并且链接函数之间不会共享范围。

我问,因为代码看起来很重复,所以我想知道是否有异常。

编辑:忘记在foo

的创建中加入bar

3 个答案:

答案 0 :(得分:1)

在我们需要之前,如何将foo存储在某个变量中?

var constructFooForUser = function(userId, data, callback) {

  var gFoo;

  db.users.find(userId)
    .then(function(user) {
      if (!user) { return callback(new Error('user not found')); }

      return db.foos.create(user, data)
    })
    .then(function(foo) {
      gFoo = foo;

      return db.bars.create(user, data)
    })
    .then(function(bar) {
      callback(null, gFoo, bar);
    })
    .catch(function(err) {
      callback(err);
    });

};

答案 1 :(得分:1)

我通常(并且我认为这是一个hacky解决方法)在我去的时候将结果累积在一个数组中。

firstThing()
  .then(first => Promise.all([first, secondThing]))
  .then(([first, second]) => Promise.all([first, second, thirdThing()]))
  .catch(e => handleErr(e));

这种积累模式有效,而且对于ES 2015解构,其笨重。

答案 2 :(得分:0)

foo和bar似乎并不依赖于彼此,所以我们可以让这部分成为并列:

var constructFooForUser = function(userId, data, callback) {
    db.users.find(userId).then(function(user) {
        //because rejecting a promise means nothing else than throwing an Error
        if(!user) throw new Error('user not found');

        //resolves as soon as both requests have been resolved. 
        //rejects if _any_ of the requests is rejecting
        return Promise.all([
            db.foos.create(user, data),
            db.foos.create(user, data)
        ]);
    }).then(
        ([foo, bar]) => callback(null, foo, bar), //utilizing array destructuring
        (err) => callback(err)
    );
}

我正在使用.then(a, b)而不是.then(a).catch(b),因为后者还会捕获回调函数中抛出的错误(我们不希望这样);你有责任处理它们。它会隐藏代码中的错误,错误消息根本不会显示在控制台中。

即使您对嵌套承诺的尝试也可以通过返回承诺并连接至少错误部分来简化

var constructFooForUser = function(userId, data, callback) {
  db.users.find(userId)
    .then(function(user) {
      if (!user) throw new Error('user not found');

      return db.foos.create(user, data)
        .then( foo => db.bars.create(user, data).then( bar => callback(null, foo, bar) ) );
    })
    .catch(function(err) {
      callback(err);
    });
};