ожидание допустимо только в асинхронной функции — nodejs

#javascript #node.js #mongodb #express #async-await

#javascript #node.js #mongodb #выразить #async-await

Вопрос:

Я использую node и express для создания сервера для моего приложения. Вот как выглядит мой код:

 async function _prepareDetails(activityId, dealId) {

  var offerInfo;
  var details = [];


  client.connect(function(err) {
    assert.equal(null, err);
    console.log("Connected correctly to server");

    const db = client.db(dbName);
    const offers_collection = db.collection('collection_name');

    await offers_collection.aggregate([
      { "$match": { 'id': Id} },
    ]).toArray(function(err, docs) {
      assert.equal(err, null);
      console.log("Found the following records");
      details = docs;
    });
  })
  return details;
}

app.post('/getDetails',(request,response)=>{

  var Id = request.body.Id;
  var activityId = request.body.activityId;
  _prepareDetails(activityId,Id).then(xx => console.log(xx));
  response.send('xx'); 
})
  

При вызове getDetails API я получаю

 await is only valid in async function error (At line await offers_collection.aggregate)
  

Я также получаю красное подчеркивание при объявлении async function . Версия узла, которую я использую, — 11.x. Я также использую firebase API. Что я здесь делаю не так?

Комментарии:

1. function(err) { должно быть async ?

2. Я считаю, что toArray создать простой массив не Promise из массива, поэтому ожидание этого на самом деле не имеет смысла для меня.

Ответ №1:

Вам не хватает объявления async в одной из ваших функций. Вот рабочий код:

 async function _prepareDetails(activityId, dealId) {

  var offerInfo;
  var details = [];


  client.connect(async function(err) {
    assert.equal(null, err);
    console.log("Connected correctly to server");

    const db = client.db(dbName);
    const offers_collection = db.collection('collection_name');

    await offers_collection.aggregate([
      { "$match": { 'id': Id} },
    ]).toArray(function(err, docs) {
      assert.equal(err, null);
      console.log("Found the following records");
      details = docs;
    });
  })
  return details;
}

app.post('/getDetails', async (request,response)=>{

  var Id = request.body.Id;
  var activityId = request.body.activityId;
  let xx = await _prepareDetails(activityId,Id);
  response.send('xx'); 
})
  

Await может использоваться только в асинхронной функции, потому что await по определению асинхронен и, следовательно, должен использовать парадигму обратного вызова или обещания. Объявляя функцию как асинхронную, вы указываете JavaScript обернуть ваш ответ в обещание. Ваша проблема заключалась в следующей строке:

   client.connect(function(err) {
  

Именно здесь я добавил асинхронность, как упоминалось ранее.

 client.connect(async function(err) {
  

Вы заметите, что я также сделал ваш маршрут асинхронным, потому что раньше у вас была бы проблема. Обратите внимание на две строки в вашем исходном коде:

   _prepareDetails(activityId,Id).then(xx => console.log(xx));
  response.send('xx'); 
  

Ваш ответ будет отправлен еще до того, как вы выполните вызов базы данных, потому что вы не завершаете ответ.отправить внутри .then. Вы могли бы переместить ответ.отправьте в .then , но если вы собираетесь использовать async / await, я бы использовал его полностью. Итак, ваш новый маршрут будет выглядеть так:

 app.post('/getDetails', async (request,response)=>{

  var Id = request.body.Id;
  var activityId = request.body.activityId;
  let xx = await _prepareDetails(activityId,Id);
  response.send('xx'); 
})
  

Комментарии:

1. Спасибо за подробный ответ. Когда я пытаюсь это сделать, я получаю пустой массив в xx. Когда я создаю console.log (подробности) в _prepareDetails, я получаю правильные данные. Но когда я делаю console.log(xx) сразу после let xx = await _prepareDetails(ActivityId, Id), он печатает пустой массив. Я попытался переместить оператор return внутри toArray, но затем он печатает undefined.

2. Возможно, вам потребуется удалить toArray после aggregate и вызвать .exec. Затем после того, как вы дадите xx = … вы можете сделать xx = xx.toArray

3. Необработанное предупреждение promiserejectionwarning: TypeError: offers_collection.aggregate(…).exec не является функцией

4. Я не так хорошо знаком с агрегатными функциями в Mongo, поэтому вы можете задать другой вопрос, если у вас возникли проблемы