【问题标题】:Dealing with nested forEach in Node.js处理 Node.js 中的嵌套 forEach
【发布时间】:2020-09-12 05:23:04
【问题描述】:

我正在做一些需要嵌套 foreach 循环来处理一些数据的事情。

我需要查找一组 ID,每个 ID 都与一个用户相关,我只需要从 API 调用的响应中提取他们的名称。服务 A 拥有 ID 列表,然后针对每个 ID 向服务 B 发送 HTTP GET 请求(无法更改),然后以

格式的正确信息进行响应
{
  success: true,
  user: {
    name: 'John Doe'
  }
}

无效但是我当前代码的代码

incidents.forEach((name) => {
    foo = {
        nameID: names 
    }
    const asyncForEach = async (array, callback) => {
        for(let index = 0; index < array.length; index++) {
            await callback(array[index], index, array)
        }
    }
    const startMulti = async () => {
    await asyncForEach(foo.nameID, async (obj, index) => {
        await userController.userInfo(obj)
            .then((userInfo) => {
                foo.nameID[index] = userInfo.user.name
            })
            .then(() => {
                foobarArray.push(foo)
            })
        })
        return res.json({success: true, foobar: foobarArray})
    }
    startMulti()

})

从这篇博客文章中获得了嵌套 foreach 循环的原始想法,这让我之前可以做另一个,尽管这个不起作用

https://codeburst.io/javascript-async-await-with-foreach-b6ba62bbf404

编辑显示变量

让 foo 让 foobarArray = []

向用户控制器添加了等待,现在可以得到正确的输出,但错误消息显示Cannot set headers after they are sent to the client

名称来自代码外部,并且只需要它所在的位置。在不完整/详细解释项目的情况下不知道如何解释。

编辑 usercontroller.userinfo 的显示代码

exports.userInfo = function(id) {
    return new Promise((resolve, reject) => {
        let user = {
            _id: id
        }
        options.json = {user}
        request.get('/userInfo', options, (err, response, body) => {
            resolve(body)
        })
    })
}

此代码按预期完美运行 - 即它使用正确的负载发送请求并返回正确的响应。

编辑当前代码尝试

let foobarArray =[]
let names = []
let foo
for (const incident of incidents) {
    foo = {
        nameID: names
    }
    for (const id of incident.names) {
        const userInfo = await userController.userInfo(id)
        names.push(userInfo.user.name)

    }
}
return res.json({success: true, fooreturned: foobarArray})

userController前面的await导致的错误信息

SyntaxError: await is only valid in async function

编辑尝试创建异步函数(我通常不使用 async/await 而是使用 Promise)

即使在下面的尝试代码之后,它仍然会给出上面的错误消息 - 我在编辑以显示错误消息之前尝试了相同的代码

exports.userInfo = async function(id) {
    return new Promise((resolve, reject) => {
        let user = {
            _id: id
        }
        options.json = {user}
        request.get('/userInfo', options, (err, response, body) => {
            resolve(body)
        })
    })
}

下面的完整代码,除了上面已经显示的 userInfo 函数。

exports.monitor = function(req, res, next) {
    const fooID = req.params.id
    let foobarArray =[]
    let names = []
    let foo
    Incident.find({fooID})
    .exec((err, incidents) => {
        if(err) {
            console.log(err)
            return res.json({success: false, foobar: []})
        }
        if(incidents != []) {           
            for (const incident of incidents) {
                foo = {
                    nameID: incident.foo[0].names
                }
                for (const id of foo.responded) {
                    const userInfo = await userController.userInfo(id)
                    names.push(userInfo.user.name)

                }
            }
            return res.json({success: true, foobar: foobarArray})
        }

    })
}

这几乎是整个代码,除了一些我还需要添加的日志记录行。我非常需要 foobar: foobarArray 成为对象数组 - foo - 其中 nameID 是专有名称数组而不是 ID。通过传递 ID 的userController.userInfo 获取专有名称。

edit - async 和 promisify 后的新代码 - 不确定我是否正确地进行了 promisify

exports.monitor = async function(req, res, next) {
    const fooID = req.params.id
    const incidents = await userController.incidentFind(fooID)

}

exports.incidentFind = async function(id) {
    return new Promise((resolve, reject) => {
        const sevenAgo = moment().subtract(7, 'days').toISOString()
        let alertArray =[]
        let names = []
        let alert
        Incident.find({monitorID, createdAt: {$gte: sevenAgo}})
        .exec((err, incidents) => {
        if(err) {
            console.log(err)
            return res.json({success: false, foobar: []})
        }
        if(incidents != []) {           
            for (const incident of incidents) {
                foo = {
                    nameID: incident.foo[0].names
                }
                for (const id of foo.responded) {
                    const userInfo = await userController.userInfo(id)
                    names.push(userInfo.user.name)

                }
            }
            return res.json({success: true, foobar: foobarArray})
        }

        })
    })
}

不确定实际的控制器monitor 应该包含什么。位丢失

错误信息

/home/me/Projects/app/incidents/controllers/users.js:100
const userInfo = await userController.userInfo(id)
                 ^^^^^

SyntaxError: await is only valid in async function

看起来该函数应该已经是异步的(将异步放在 function 名称之前)。

【问题讨论】:

  • 您永远不会等待来自userController.userInfo() 的承诺。此外,您的代码中有多个未声明的变量,您不能多次发送响应。
  • @Bergi 没有未声明的变量,它们是在代码显示之外声明的。我知道它多次发送响应,但是我不知道如何让它只发送一次而不跳过其他代码 - 这是一个问题
  • 请发布完整示例所需的全部代码。否则我们无法判断实际问题是什么,到目前为止我还没有回答,因为我不知道如何在适当的解决方案中对待foobarArray
  • @Bergi 在上面的代码之外有两个变量,foo。至于 foobarArray,它从一个空数组开始,在上述代码的第 16 行,它显示了一个推入 foo 的数组。然后是 foo ,它只在 foo 附近添加 nameID 的顶部附近被引用。这就是这段代码中显示的所有变量。如果我将 await 添加到 userController 部分,它会给我正确的输出,但它也会在节点控制台中给我一条错误消息,说 Cannot set headers after they are sent to the client 我预期但不确定如何解决
  • 你可以在edit 你的问题中包含这些:-) 另外,names 是什么?

标签: javascript node.js foreach nested-loops


【解决方案1】:

我想你正在寻找一个简单的

exports.monitor = async function(req, res, next) {
    const fooID = req.params.id
    const foobarArray = […]
    const names = […]
    try {
        const incidents = await Incident.find({fooID}).exec()
        for (const name of incidents) {
            const foo = {
                nameID: []
            }
            for (const userId of names) {
                const userInfo = await userController.userInfo(userId)
                foo.nameID.push(userInfo.user.name)
            }
            foobarArray.push(foo)
        }
        res.json({success: true, foobar: foobarArray})
    } catch(err) {
        console.log(err)
        res.json({success: false, foobar: []})
    }    
}

【讨论】:

  • 看起来它可能有效,唯一的问题是foo.nameID 是 userInfo 替换的 ID 数组,我如何获取索引或替换正确的索引?
  • 您可能不想替换它们,而是创建一个新数组并将它们放入其中。更新了我的答案。
  • 当然猜,只是它需要成为 fooArray 的一部分,因为我将它返回给客户端,所以我不会太挑剔我是怎么做的
  • 一直在玩代码,看看我能不能让它工作,但没有运气。放入一些console.log 以查看启动的顺序。在用户控制器能够发送和接收请求之前将响应发送回。 console.log 也意识到它正在复制 foobadArray 中的 events/foo
  • @joshk132 在答案的第一版中,我错过了await - 你在尝试的代码中有这个吗?另外,是的,它会创建重复项,因为事件名称永远不会在任何地方使用来获取不同的userInfo
猜你喜欢
  • 2016-06-17
  • 1970-01-01
  • 2010-11-18
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 2017-05-09
  • 2014-01-18
  • 1970-01-01
相关资源
最近更新 更多