NodeJS查询处理结果设计模式避免嵌套的then语句

时间:2019-05-29 20:15:02

标签: node.js asynchronous design-patterns

我正在用NodeJS10和Mongoose5编写一个应用程序。我正在编写自定义服务器端分页功能。我想在控制器中运行分页,以分离关注点和可重用性。

我有一个查询以获取数据并在then()响应处理程序中将其返回。然后,我在then()处理函数中调用自定义分页功能。这行得通,但我担心“嵌套”的接/接模式。我认为这可能很麻烦,特别是如果返回响应之前需要对数据进行任何其他处理。

这是“嵌套”结构。我该如何改进它以使其不再嵌套且更具可读性,同时仍然捕获所有可能的错误并正确返回响应?请注意,这可以正常工作,只是设计模式比较混乱,如果可能的话,我想避免使用“嵌套”的then()语句。

router.get('/:id', (req, res, next) => {
  const origin = 'routes/items.js GET /:id';

  const id = req.params.id;

  items.find({
    _id: id
  }).then(data => {

    uiCtrl.pagination(data, req.query).then((result) => {
      res.status(200).send(result);
    }).catch((error) => {
      console.error(`pagination failed ${error}`);
      res.status(500).send(`pagination failed ${error}`);
    });

  }).catch((error) => {
    console.log(`${origin} ${error}`);
    res.status(404).send('Not found');
  });

});

这是在上面的查询结果中调用的自定义异步函数。

const uiCtrl = {};

uiCtrl.pagination = async (data, query) => {

  // pagination logic here
  return data;
}

module.exports = uiCtrl;

2 个答案:

答案 0 :(得分:1)

这里是使用普通async/await东西的重写:

var data, results;
try {
   data = await items.find({_id:id}).toArray();
}
catch (err) {
   console.log(`${origin} ${error}`);
   res.status(404).send('Not found');
}
try {
   results = await uiCtrl.pagination(data, req.query);    
}
catch (err) {
   console.error(`pagination failed ${error}`);
   res.status(500).send(`pagination failed ${error}`);
}

应该注意的是,鉴于我对您的代码一无所知,您可能还有其他一些事情可以使代码更易于阅读和使用(例如,拒绝承诺并对其做出有意义的事情,而不是抛出异常。您还需要将所有这些代码包装在async方法中,以便可以使用await关键字。

编辑

为了完整起见,现在给出完整的代码,我将以如下方式开始:

router.get('/:id', async (req, res, next) => {
  const origin = 'routes/items.js GET /:id';

  const id = req.params.id;

  var itemResults, paginationResults;
  try {
     itemResults = await items.find({_id: id}).toArray();
  }
  catch (err) {
     console.log(`${origin} ${error}`);
     res.status(404).send('Not found');
  }
  try {
     paginationResults = await uiCtrl.pagination(data, req.query);
     res.status(200).send(result);
  }
  catch (err) {
     console.error(`pagination failed ${error}`);
     res.status(500).send(`pagination failed ${error}`);
  }
});

作为一种优化或整理工作,我要做的另一件事是将捕获到的错误移到单个catch块中,然后在那里解析错误,以使事情更简洁。

在讨论名为callback hell的东西时也要包含此内容,这与您要查询的信息非常相关。

http://callbackhell.com/

答案 1 :(得分:0)

这是根据接受的答案重新设计的解决方案。我收到此错误,我认为这是由于直接在路由器定义中放置了'async'关键字,例如(node:3564) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1) (node:3564) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.。也许是因为在这种格式下,它不是用then或catch处理的。

router.get('/', (req, res, next) => { const origin = 'routes/items.js GET /'; async function queryWrapper() { let data, results; try { data = await items.find(); console.log(`data ${data}`); } catch (err) { console.log(`${origin} ${err}`); } try { results = await uiCtrl.pagination(data, req.query); } catch (err) { console.error(`pagination failed ${err}`); } if (results) { return results; } else { return false; } } queryWrapper().then((result) => { res.status(200).send(result); }).catch((error) => { console.error(`${error}`); res.status(500).send(`${error}`); }); });

最后我得到了一个稍微修改的解决方案,我做了一个包装器函数,然后用then()处理函数调用了它。谢谢!

{{1}}