首页 > 解决方案 > NodeJS等待/异步使数据检索同步

问题描述

我知道这已经问了数千次了,但我仍然无法找到答案。我有一个 forEach 循环,用于循环遍历用户列表并检索每个用户的特定位置数据。在 forEach 中,第一个函数调用获取分支,然后第二个函数调用获取该分支的信息。

问题是 forEach 循环在从函数返回数据之前没有完成,这会导致各种问题。

这是我的代码:

//getAllUserData() - this is the function which returns prematurely
const getAllUserData = async () => {

    const sequelize = DB.GetDB('mcaintranet');
    const userDB = MCAIntranet.initModels(sequelize);

    userDB.tblUsers.belongsTo(userDB.tblSMSSent, { foreignKey: 'collector', targetKey: 'user' });
    userDB.tblSMSSent.hasMany(userDB.tblUsers);

    let users = await userDB.tblUsers.findAll({
        attributes: ['collector', 'id'],
        include: {
            model: userDB.tblSMSSent,
            attributes: [[sequelize.fn('COUNT', 'tblSMSSent.id'), 'numMessages']]
        },
        raw: true,
        group: ['collector', 'tblUsers.id'],
    })

    //return list of all users and texts sent
    //UserName, User Province Code, # Messages Sent, user  Number

    try {
        await users.forEach(async user => {
            const branch = await Users.getUserBranch(user);
            const province = getKey(branch);
            user.province = province;
            // console.log("User: ", [user, branch])
            //clean up JSON from join results
            user.numMessages = user["tblSMSSent.numMessages"];
            delete user["tblSMSSent.numMessages"];
        })

        const obj = { 'users': users };
        console.log("DONE: ", obj)
        return obj;
    }
    catch (ex) {
        console.log("ERROR: ", ex)
        const msg = ex.Message;
        return { results: "False", message: "SMS.js 61" + msg }; //is user allowed to use SMS page)
    }
}
//getUserBranch() - accessor function to return branch number
const getUserBranch = async (user) => {
    // console.log("Branch User: ", user)
    let branch = getUserProps(user.collector ? user.collector : user, 'branch');
    // console.log(props)
    if (!branch) branch = 0;
    return branch;
}
//getUserProps - pulls all user properties from database and filters as necessary
const getUserProps = async (user, propName = null) => {
    let ret = {};

    if (user.collector) user = user.collector;
    user = user.trim();
    let filter = {
        collector: user
    }
    if (propName) {
        filter.propertyName = propName
    }

    // console.log("Filter: ", filter)
    const sequelize = DB.GetDB('MCAIntranet');
    const propsDB = MCAIntranet.initModels(sequelize);

    //get all values contained for user
    let props = await propsDB.tblUserProperties.findAll({
        attributes: ['id', 'propertyName', 'propertyValue', 'updated'],
        where: filter,
        order: [['updated', 'DESC']],
    })

    // console.log("Props: ", props);

    let distinctProps = await propsDB.tblUserProperties.findAll({
        attributes: ['propertyName'],
        DISTINCT: true,
        where: filter,
    })

    //the SMS Credits item is sometimes added as a second row
    //so loop through all potential value rows for user
    distinctProps.forEach(dr => {
        // console.log(dr);
        var name = dr.propertyName.toLowerCase();
        // console.log("name: ", name)
        try {
            //get individual values for each property user possesses
            let tmpRows = props.filter(row => row.propertyName.toLowerCase() == name);
            // console.log("tmpRows: ", tmpRows)

            //get the most recent value
            let row = tmpRows[tmpRows.length - 1];
            var item = row.propertyName.trim();
            var value = row.propertyValue.trim();
            //add to returned JSON
            ret[item] = value;
        } catch (ex) {
            console.log("USERS.js 157 " + ex.message);
            return ({ error: "USERS.js 158" + ex.Message });
        }
    })
    // console.log("Ret: ", ret)
    return ret;
}
//getKey() - returns necessary data about the user province
const getKey = (data) => {
    let branch;
    try {
        branch = data.branch ? data.branch : data;
    }
    catch (ex) {
        console.log(data)
        console.log(ex)
    }
    branch = parseInt(branch);
    // console.log(branch)
    try {
        let acctKey = "";
        let province = "";
        let abbr = "";
        // console.log("Branch: ", branch)
        switch (branch) {
            case 4: //vancouver
            case '4':
                abbr = "BC";
                acctKey = key["BC"];
                province = "British Columbia";
                break;
            case 7: //Montreal
            case '7':
                abbr = "QC";
                acctKey = key["QC"];
                province = "Quebec";
                break;
            case 9: //Toronto
            case '9':
                abbr = "ON";
                acctKey = key["ON"];
                province = "Ontario";
                break;
            default: //Edmonton
                abbr = "AB";
                acctKey = key["AB"];
                province = "Alberta";
                break;
        }
        return { key: acctKey, province: province, abbr: abbr };
    }
    catch (ex) {
        throw ex;
    }
}

在等待和异步的集合中的某个地方缺少某些东西,导致 getAllData() 函数返回没有位置数据的用户名。在获得所有数据之前,如何阻止执行?请忽略我在努力解决这个问题时所付出的额外等待。

谢谢。

标签: javascriptnode.jsasync-await

解决方案


而不是forEach,你想要这个:

await Promise.all(users.map(async (user) => {...}))

map 返回每个内部操作的承诺,并且await-ing Promise.all等待所有这些承诺完成


推荐阅读