Проблема с асинхронными функциями при передаче данных в массивы [дубликаты]

1

В настоящее время у меня огромные проблемы при работе с асинхронной функцией. Первое, что я пытаюсь сравнить мой deleteArray (который содержит текущие данные, которые должны быть в коллекции) с данными в коллекции.

 static async updateDocsInCollection(data) {
        let deleteArray= [];

        // Insert all data into array.
        data.forEach(async (elem) => {
            deleteArray.push(elem.serial);
        }

        MongoClient.connect('mongodb://' + config.database.host + ':' + config.database.port, { useNewUrlParser: true }, async function(err,db){
        if (err) throw err;

        // Get the current documents from "inventory" collection".
        await dbo.collection("inventory").find({}).toArray(function(err, res) {
                if (err) throw err;

                // Iterate through res array and see if res element exists in
                // deleteArray
                res.forEach((elem) =>{
                    if(!deleteArray.includes(elem.serial)){
                        // if it don't, push it.
                        deleteArray.push(elem)
                        console.log(elem.serial + " Pushed into array");
                    }

                });

            });

         // Iterate through deleteArray and delete it from collection.
         deleteArray.forEach((elem) =>{
               console.log(elem);
               dbo.collection("onlineplayerservice").findOneAndDelete({ 'serial': elem.serial});
            }); 

         // closing db-connection.
         db.close();
        });  

Проблема заключается в том, что код не выполняется в правильном порядке, потому что я не могу перебрать deleteArray, хотя я вижу (согласно console.log), что данные вводятся туда.

Есть ли у вас какие-либо советы о том, как я могу обеспечить синхронизацию этой функции?

  • 1
    Пожалуйста, прочитайте также Как правильно повторно использовать соединение с Mongodb через приложение и модули NodeJ, поскольку вы никогда не включаете соединение с базой данных в обычно вызываемую функцию. Также обратите внимание, что хотя вы получили ответ, исправляющий вас в семантике JavaScript асинхронных методов, все части MongoDB по-прежнему неверны. Вы должны в основном ссылаться на связанные ответы и эту дополнительную ссылку для структуры и использования.

1 ответ

2

Проблема в том, что вы используете async функцию внутри вашего первого forEach(). Это означает, что вы выполняете итерацию своего массива с асинхронными функциями, возвращающими Promises, поэтому код не будет ждать завершения forEach перед переходом к следующему оператору.

Прямой ответ:

Я не вижу никакой причины, по которой у вас здесь есть async поэтому я бы просто удалил ее. Но если вам это действительно нужно, вот что вы должны сделать:

// Will wait for all lambda async function inside the forEach to finish
await Promise.all(data.forEach(async (elem) => {
   deleteArray.push(elem.serial);
}));

Советы и исправления:

В качестве подсказки, если все, что вам нужно, это получить атрибут serial всех ваших элементов data, вы должны использовать Arrays.map следующим образом:

let deleteArray = data.map(function(elem) { return elem.serial; });

Другое дело, вы должны выбрать, использовать ли обратные вызовы или Promises с async/await, а не оба:

// Wrong
await dbo.collection("inventory").find({}).toArray(function(err, res) {});

// Good with promise and await
let res = await dbo.collection("inventory").find({}).toArray();

// Good with callback
dbo.collection("inventory").find({}).toArray(function(err, res) {});

Полный фиксированный пример кода:

static async updateDocsInCollection(data) {
    // Insert all data into array.
    let deleteArray = data.map(function(elem) { return elem.serial; });

    const dbo = await MongoClient.connect('mongodb://' + config.database.host + ':' + config.database.port, { useNewUrlParser: true });

    // Get the current documents from "inventory" collection".
    const res = await dbo.collection("inventory").find({}).toArray();  
    // Iterate through res array and see if res element exists in deleteArray
    res.forEach((elem) =>{
        if(!deleteArray.includes(elem.serial)){
           // if it don't, push it.
           deleteArray.push(elem.serial) // You forgot the .serial here
           console.log(elem.serial + " Pushed into array");
        }
    });

     // Iterate through deleteArray and delete it from collection.
     // The deleteArray already contains serials, not data elements
     deleteArray.forEach((serial) =>{
          console.log(serial);
          dbo.collection("onlineplayerservice").findOneAndDelete({ 'serial': serial});
     }); 

     // closing db-connection.
     db.close();
});  
  • 1
    Привет Kapcash Большое спасибо за ваш ответ и советы о том, как улучшить код. Я чувствую, что понимаю немного больше о том, использовать ли Callbacks или Promises с асинхронным. Несмотря на изменения, кажется, что код не выполняется в правильном порядке. Нужно ли мне что-то изменить в фрагменте dbo.collection (inventory), чтобы он мог завершиться до того, как deleteArray.forEach () запустится в конце?
  • 1
    Я добавил полный исправленный код, пожалуйста, попробуйте. Я не проверял код, поэтому он все еще может содержать ошибки компиляции или что-то в этом роде. Во всяком случае, вот как вы должны async / await. Попробуйте ввести свой код в режиме отладки, чтобы увидеть, как он выполняется.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню