使用多个.then修正JavaScript的评估顺序

时间:2018-05-28 20:46:26

标签: javascript node.js promise

我很难在JavaScript中使这段代码同步。

评论(1,2和3)表示按顺序发生的事情,现在它可能会在创建新栏之前保存所有者。

我需要findOne,可能是saveBar,然后是saveOwner。

function setMyBar(req, res, next) {
  const owner = req.queryOwner;
  Bar.findOne({
    placeId: req.body.placeId
  })
    .then((bar) => {
      if(bar){
        owner.bar = bar; //1
        return owner;
      }else{
        barCtrl.saveBar(req.body.name, req.body.placeId, req.body.longitude, req.body.latitude)
        .then((savedBar) => {
          owner.bar = savedBar; //3
          return owner;
        })
        .catch(e => {return Promise.reject(err) })
      }
    }).then(() => {
      owner.save()
        .then(savedOwner => res.json(savedOwner)) //2
        .catch(e => next(e));
    })
    .catch(e => next(e));
}

4 个答案:

答案 0 :(得分:2)

您需要在then()条件的第一个else中返回承诺。现在没有返回任何内容,所以它会在then解析之前跳转到下一个barCtrl.saveBar()

尝试

 Bar.findOne({
    placeId: req.body.placeId
  })
    .then((bar) => {
      if(bar){
        owner.bar = bar; //1
        return owner;
      }else{
       // return this promise
       return barCtrl.saveBar(req.body.name, req.body.placeId, req.body.longitude, req.body.latitude)
        .then((savedBar) => {
          owner.bar = savedBar; //3
          return owner;
        })
        .catch(e => {return Promise.reject(err) })
      }
    }).then(() => {
      owner.save()
        .then(savedOwner => res.json(savedOwner)) //2
        .catch(e => next(e));
    })
    .catch(e => next(e));

答案 1 :(得分:0)

试试这个

function setMyBar(req, res, next) {
  const owner = req.queryOwner;
  Bar.findOne({
    placeId: req.body.placeId
  })
    .then((bar) => {
      if(bar){
        owner.bar = bar; //1
        return owner;
      }else{
        // return should do the magic
        return barCtrl.saveBar(req.body.name, req.body.placeId, req.body.longitude, req.body.latitude)
        .then((savedBar) => {
          owner.bar = savedBar; //3
          return owner;
        })
        .catch(e => {return Promise.reject(err) })
      }
    }).then(() => {
      owner.save()
        .then(savedOwner => res.json(savedOwner)) //2
        .catch(e => next(e));
    })
    .catch(e => next(e));
}

当您在承诺中返回某些内容时,它将作为承诺返回。 并且承诺你当前的承诺必须回报承诺。你不在哪里

答案 2 :(得分:0)

您可以使用承诺链简化很多:

function setMyBar(req, res, next) {
  Bar.findOne({
    placeId: req.body.placeId
  }).then(bar => {
    if (bar) {
      return bar;
    } else {
      return barCtrl.saveBar(req.body.name, req.body.placeId, req.body.longitude, req.body.latitude);
    }
  }).then(savedBar => {
    const owner = req.queryOwner;
    owner.bar = savedBar;
    return owner.save();
  }).then(savedOwner => {
    res.json(savedOwner);
  }, e => {
    next(e);
  });
}

重要的变化:

  • return saveBar承诺,以便等待它,您可以在下一个(外部)then回调中使用其结果
  • ownwer.bar作业分配给下一个回调,如果查询已经找到,则只需return bar,以避免代码重复
  • 放弃毫无意义的.catch(e => {return Promise.reject(err) })

答案 3 :(得分:0)

您还可以尝试使用ES7异步函数或async / await语法,这样您就可以编写代码。如果您愿意,还可以异步和并行执行代码。主流浏览器的所有当前版本(IE除外)以及Node.js使用的Google V8引擎都支持它。

我很快就破解了你的代码以使用async / await语法,可能会出现奇怪的错误,因为我只是想向你展示使用异步函数的优点。看起来应该是这样的:

async function setMyBar(req, res, next) {
    const owner = req.queryOwner;
    try {
        let bar = await Bar.findOne({
            placeId: req.body.placeId
        });

        if (bar) {
            owner.bar = bar;
        } else {
            let savedBar = await barCtrl.saveBar(req.body.name, req.body.placeId, req.body.longitude, req.body.latitude);
            owner.bar = savedBar;
        }

        res.json(await owner.save());
    } catch (e) {
        next(e);
    }
}

另请注意,异步函数声明中的async关键字可确保您的函数始终返回promise!

阅读有关功能的一些很棒的链接,还提供了有关承诺的更多背景信息:

https://developers.google.com/web/fundamentals/primers/async-functions

https://medium.com/@bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8