node.js 中的 foreach 异步函数

Posted

技术标签:

【中文标题】node.js 中的 foreach 异步函数【英文标题】:foreach async function in node.js 【发布时间】:2016-08-17 13:53:27 【问题描述】:

我想遍历每个学生,然后执行两个查询,这两个查询的执行应该是同步的,首先是第一个,然后因为第二个查询取决于第一个。

我已经写了一些代码,但它似乎根本不起作用:

Student.find( status: 'student' )
    .populate('student')
    .exec(function (err, students) 
        if (err) 
            return res.status(400).send(
                message: errorHandler.getErrorMessage(err)
            );
        

        _.forEach(students, function (student) 
            async.waterfall(
                [
                    function (callback) 
                        console.log('first ' + student.firstName);
                        Student.find( "_id": student.id , callback);
                    ,
                    function (student, callback) 
                        console.log('second '+ student[0].firstName);
                        WorksnapsTimeEntry.find(
                            "student": 
                                "$in": student.map(function (el) 
                                    return el._id
                                )
                            
                        , callback);
                    
                ],
                function (err, results) 
                    if (err) 
                        // do something
                     else 
                        // results are the matching entries
                        console.log('third');
                        var totalMinutes = 0;
                        var totalAvgLevelActivity = 0;
                        var counter = 0;
                        _.forEach(results, function (item) 
                            _.forEach(item.timeEntries, function (item) 
                                if (item.duration_in_minutes) 
                                    totalMinutes = totalMinutes + parseFloat(item.duration_in_minutes[0]);
                                

                                if (item.activity_level) 
                                    totalAvgLevelActivity = totalAvgLevelActivity + parseFloat(item.activity_level[0]);
                                    counter++;
                                
                            );
                        );

                        var obj = ;
                        obj.studentId = 'test';
                        obj.firstName = 'test';
                        obj.lastName = 'test';
                        obj.municipality = 'test';
                        obj.totalMinutes = totalMinutes;
                        obj.totalAvgLevelActivity = totalAvgLevelActivity / counter;
                        arrayReports.push(obj);
                        // console.log('not yet finished.');
                    
                
            );
        );

        res.json(arrayReports);
        console.log('finished.');

任何人都知道如何在 Node.js 中实现这一目标

【问题讨论】:

你有输出吗? 是的,我可以看到打印学生的名字,但我不确定他们是否以那种方式打印,第一个学生必须完成所有事情,直到第二个学生开始......还有 res.json (arrayReports) 始终为空,因为它当然是在 foreach 中的那些查询完成之前执行的,有没有什么方法可以等到全部完成然后执行 res.json() 我猜你用错了async.waterfall。从每个任务函数中,您需要使用合适的参数调用下一个函数 【参考方案1】:

mongoose 已被承诺,您不必使用async 来处理流程,也不必为简单的 forEach 使用 lodash。而且您通过 _id 请求查找是没用的,您已经有一个 Student 对象:

Student.find( status: 'student' )
    // .populate('student') // why this?
    .then(function (students) 
        // build an array of promises
        var promises = students.map(function (student) 
            return WorksnapsTimeEntry.find(
                "student": student._id;
            );
        );

        // return a promise to continue the chain
        return Promise.all(promises);
    ).then(function(results) 
        // results are the matching entries
        console.log('third');
        var totalMinutes = 0;
        var totalAvgLevelActivity = 0;
        var counter = 0;
        _.forEach(results, function (item) 
            _.forEach(item.timeEntries, function (item) 
                if (item.duration_in_minutes) 
                    totalMinutes = totalMinutes + parseFloat(item.duration_in_minutes[0]);
                

                if (item.activity_level) 
                    totalAvgLevelActivity = totalAvgLevelActivity + parseFloat(item.activity_level[0]);
                    counter++;
                
            );
        );

        var obj = ;
        obj.studentId = 'test';
        obj.firstName = 'test';
        obj.lastName = 'test';
        obj.municipality = 'test';
        obj.totalMinutes = totalMinutes;
        obj.totalAvgLevelActivity = totalAvgLevelActivity / counter;
        arrayReports.push(obj);
        // console.log('not yet finished.');
        res.json(arrayReports);
        console.log('finished.');
    ).catch(function(err) 
        return res.status(400).send(
            message: errorHandler.getErrorMessage(err)
        );
    );

【讨论】:

真棒,漂亮,干净,最重要的是,可行:) thnx

以上是关于node.js 中的 foreach 异步函数的主要内容,如果未能解决你的问题,请参考以下文章

node.js 中的异步函数完成后如何运行函数?

node.js中的forEach是同步还是异步

node.js中的forEach是同步还是异步

Node.js:async.series 中的 forEach

node.js中的forEach是同步还是异步

Node.JS:forEach 与 for 循环异步性质