Асинхронизация / ожидание в Express с несколькими запросами MongoDB - PullRequest
0 голосов
/ 16 декабря 2018

У меня довольно простое приложение CRUD, которое отображает результаты двух запросов на одной странице.Проблема, которая возникла, как только я заставил это «работать», состояла в том, что страница требовала обновления, чтобы отобразить результаты.При первой загрузке результаты не отображались.

Я пришел к выводу, что это проблема / симптом асинхронного характера узла.Я пытался подойти к этой проблеме, используя async / await, и после нескольких часов возни с вещами я чувствую, что довольно близок к решению, но оно просто не работает - мне все еще нужно обновить вручную, чтобы отобразить/ рендерить результаты на странице .ejs.

Код:

var entries = [];
var frontPageGoals = [];

app.get('/entries', async (req,res) => {
  if (req.session.password) {

      const entriesColl = await 
            db.collection('entries')
            .find()
            .sort({date: -1})
            .toArray((err, result) => {
               if (err) { console.log(err) }
               else {
                  for (i=0; i<result.length; i++) {
                       entries[i] = result[i];
                  }
               }
            });

      const goalsColl = await 
            db.collection('goals')
            .find()
            .toArray((err, result) => {
               if (err) {console.log(err)}
               else {
                  for (i=0; i<result.length; i++) {
                       frontPageGoals[i] = result[i];
                  }
               }
            });

      res.render('index.ejs', {entries: entries, frontPageGoals: frontPageGoals});
   }
   else {
      res.redirect('/');
   }
 });

Теперь я могу представить себе несколько проблем здесь, но, честно говоря, я просто нахожусь в своем уме, пытаясьчтобы понять это.Например, я уверен, что проблематично, что пустые списки, которые будут содержать результаты, которые будут переданы при рендеринге страниц, находятся вне фактической асинхронной функции.Но после попытки переместить их в дюжину разных мест в пределах асинхронной области ... все еще нет игральных костей.

Любая помощь будет чрезвычайно цениться!По сути, это последняя большая «вещь», которую мне нужно сделать для этого приложения.

1 Ответ

0 голосов
/ 16 декабря 2018

Я не уверен на 100% в вашем драйвере базы данных, но при условии, что toArray() возвращает обещание (что он делает в драйвере mongodb по умолчанию), await фактически вернет значение, которое вы ожидаете в обратном вызове, result в вашем случае, или если произошла ошибка, которую вы ожидали как err в вашем обратном вызове, она будет выброшена, что заставит вас использовать блоки try-catch, в вашем случае вы простоиспользуйте console.log(err) в блоке catch, поскольку вы не выполняете никакой обработки

Вот ваш код после обновления:

app.get("/entries", async (req, res) => {
  if (req.session.password) {
    try {
      const entries = await db
        .collection("entries")
        .find()
        .sort({ date: -1 })
        .toArray();

      const frontPageGoals = await db
        .collection("goals")
        .find()
        .toArray();

      res.render("index.ejs", {
        entries: entries,
        frontPageGoals: frontPageGoals
      });
    } catch (err) {
      console.log(err);
    }
  } else {
    res.redirect("/");
  }
});

EDIT

Однако, если вы не знаете об обещаниях, которые async/await в основном являются обещаниями, и хотите просто сделать это с помощью обратных вызовов - не рекомендуется -, вам придется просто отправить свой ответ в обратном вызовеи вложите 2-й запрос в обратный вызов первого запроса, вот код с некоторыми комментариями, которые, надеюсь, помогут вам:

app.get("/entries", (req, res) => {
  if (req.session.password) {
    // First query
    db.collection("entries")
      .find()
      .sort({ date: -1 })
      .toArray((err, entryResult) => {
        if (err) {
          console.log(err);
        } else {
          // In the callback of the first query, so it will
          // execute 2nd query, only when the first one is done
          db.collection("goals")
            .find()
            .toArray((err, frontPageResult) => {
              if (err) {
                console.log(err);
              } else {
                // In the callback of the 2nd query, send the response
                // here since both data are at hand
                res.render("index.ejs", {
                  entries: entryResult,
                  frontPageGoals: frontPageResult
                });
              }
            });
        }
      });
  } else {
    res.redirect("/");
  }
});
  • Я удалил ключевое слово async, так как вы небольше не нужно
  • я переименоваларгументы обратного вызова, а не просто result, потому что оба обратных вызова будут иметь одинаковое имя аргумента, и вам придется хранить его во временной переменной
...