Node.js forEach函数不等待异步函数

时间:2020-02-25 23:48:14

标签: node.js mongodb loops async-await

我正在尝试获取json,并与mongodb检查是否存在重复项(如果不存在),然后将数据插入mongodb。

问题在于循环非常快,无需等待重复的检查和插入。

我在做什么错了?

const fetch = require('node-fetch');
var MongoClient = require('mongodb').MongoClient;


async function fetchPhotos() {
    MongoClient.connect("mongodb://localhost:27017", async function (err, dbo) {
        const db = dbo.db('mydb')
        if (err) throw err;
        for (var i = 1; i < 100; i++) {
            await fetch(`domain.com/?page=${i}`)
               .then(res => res.json())
                .then((response) => {
                    response.forEach(photo => {
                        console.log("checking if there is duplicate: " + photo.id);

                        var exists =  db.collection("photos").countDocuments({"id": photo.id}, {limit: 1});

                        if (exists === 1) {
                            console.log("dupl found, next!");

                        } else {
                            db.collection("photos").insertOne(photo, function (err, res) {
                                if (err) throw err;
                                console.log("1 document inserted");
                            });
                        }
                    });
                });

        }

    });
}

module.exports.fetchPhotos = fetchPhotos;

1 个答案:

答案 0 :(得分:2)

循环中异步代码存在一些问题。

  1. .forEach()循环不等待await。如果要让它等待for,则必须使用while循环或await循环。
  2. 您没有在await上使用db.collection("photos").countDocuments({"id": photo.id}, {limit: 1});
  3. 您没有在await上使用db.collection("photos").insertOne(photo)
  4. 请勿在相同的控制流中混合普通的回调和Promise。这使得安全编码和适当的错误处理非常困难。
  5. 您在许多地方都缺少适当的错误处理。

您可以重组整个内容,以使用数据库的Promise接口,然后通过照片对迭代进行排序,并简化如下操作:

const fetch = require('node-fetch');
var MongoClient = require('mongodb').MongoClient;

async function fetchPhotos() {
    const dbo = await MongoClient.connect("mongodb://localhost:27017");
    const db = dbo.db('mydb');
    for (let i = 1; i < 100; i++) {
        let response = await fetch(`http://example.com/?page=${i}`);
        let data = await response.json();
        for (let photo of data) {
            console.log("checking if there is duplicate: " + photo.id);
            let cnt = await db.collection("photos").countDocuments({"id": photo.id}, {limit: 1});
            if (cnt > 0) {
                console.log("dupl found, next!");
            } else {
                await db.collection("photos").insertOne(photo);
                console.log("photo inserted");
            }
        }
    }
}

// caller of fetchPhotos() gets a promise that tells you if the 
// operation completed or had an error
module.exports.fetchPhotos = fetchPhotos;