Я пишу приложение в NodeJS10 и Mongoose5. Я пишу пользовательскую функцию разбиения на страницы на стороне сервера. Я хочу запустить нумерацию страниц в контроллере для разделения проблем и повторного использования.

У меня есть запрос, чтобы получить данные и вернуть их в обработчик ответа then (). Затем я вызываю пользовательскую функцию разбиения на страницы внутри обработчика then (). Это работает, но меня беспокоят "вложенные" шаблоны then / catch. Я думаю, что это может быть грязно, особенно если требуется дополнительная обработка данных перед возвратом ответа.

Вот «вложенная» структура. Как я могу улучшить это, чтобы оно больше не было вложенным и более читабельным, при этом все еще перехватывая все возможные ошибки и возвращая правильный ответ? Заметьте, что это работает просто отлично, просто шаблон проектирования запутан, и я хочу по возможности избегать «вложенных» операторов 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;
0
pengz 29 Май 2019 в 23:15

2 ответа

Лучший ответ

Вот переписать, используя обычный 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
Michael Platt 29 Май 2019 в 20:42

Вот переработанное решение, основанное на принятом ответе. Я получил эту ошибку, думаю, это связано с размещением ключевого слова async непосредственно в определении маршрутизатора, например, router.get('/', async (req, res, next) . Возможно, потому, что в этом формате он не обрабатывается с помощью функции catch или catch.

(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 (). Спасибо!

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}`);
      });
});
0
pengz 29 Май 2019 в 20:57