我的回调与预期的节点 js 不同

Posted

技术标签:

【中文标题】我的回调与预期的节点 js 不同【英文标题】:My callback doesn't behave as expected node js 【发布时间】:2019-05-24 09:50:19 【问题描述】:

我要做的是首先从学生集合中获取特定年级和班级的所有学生。然后使用请求的年级和班级中的学生 ID,使用 mongoose 使用 Marks 集合中的这些学生 ID 查找标记

这是我的学生架构

const StudentSchema = new Schema(
    base_no:
        type: String,
        required: true 
    ,
grade: 
        type: Number,
        required: false
    ,
    class: 
        type: String,
        required: false
    

);

const Student = module.exports = mongoose.model('student',StudentSchema,'student');

然后我在 Student 模型中有一个这样的方法来获取特定年级和特定班级的所有学生

/**
 *  Get all students of a class for a given grade
 * 
 */
module.exports.getStudentsGradeClass = function(params,callback)
    Student.find(grade: params.grade, class: params.class,'base_no first_name last_name').sort(base_no: 1).exec(callback);

这是我的标记架构

 const MarksSchema = new Schema(

        verifire: 
            type: String,
            required: true,
            //index:true
        ,
        student_base_id:  // as student auto gen key/index no
            type: String,
            required: true,
            //index:true
        ,
        subject_id: 
            type: String,
            required: true,
            ref: 'subject',
            //index:true
        ,
        total: 
            type: Number,
            required: true
        
    );


    const Marks = module.exports = mongoose.model('school_marks', MarksSchema, 'school_marks');

所以我正在使用上述 Student Schema 的 getStudentsGradeClass() 从客户端获取请求学生的方法 然后使用此代码的 getStudentsGradeClass() 方法中的学生 ID 从 Marks 架构中获取分数

    /**
         *  Get marks of all students of the requested grade->class with subject_id
         * 
         */
        module.exports.getClassResults = function (params, callback) 
            let marks = [];
            Student.getStudentsGradeClass( grade: params.grade, class: params.class , (err, students) => 
                if (!err) 
                    for (let i = 0; i < students.length; i++) 
                        Marks.find( subject_id: params.subject_id, student_base_id: students[i].base_no , 'student_base_id total', (err, data) => 
                            if (!err) 
                                marks.push(data[0]);
                             else 
                                callback(err, null);
                            
                        );
                    
                    callback(null,marks); // this is the function I wan to invoke
                                          // right after the for loop finishes so 
                                          // that i can get all marks of all 
                                          //students for a specific subject..   


    // currently it is undefined(marks[]) coz it goes straight for the callback 
     //  giving control to the for loop, the for loop gives data much later so that 
    // marks are not pushed to the array when I call it.

                 else 
                    callback(err, null);
                

            );
        

那么我可以这样做吗(我知道我在末日金字塔中)。请建议我一种更清洁的方法来做到这一点,或者你能指导我克服这个问题或如何实现我想要达到的目标。非常感谢任何帮助。

【问题讨论】:

伙计们,我被困住了,请 > 请给我建议一个更干净的方法来做到这一点。如果有可以选择数据库类型,使用 PostgreSQL 或其他 RDMS 并使用 SQL JOIN。 其实我用的是 MEAN 栈所以不能改变数据库 有没有办法做到这一点?? 伙计们请任何事情......! 【参考方案1】:

你可以试试 async/await ...........

 module.exports.getClassResults =  (params, callback)=> 
            let marks = [];
            Student.getStudentsGradeClass( grade: params.grade, class: params.class ,async (err, students) => 
                if (!err) 

                 for (let student of students)
                      let data=await Marks.find( subject_id: params.subject_id, student_base_id: student.base_no , 'student_base_id total')
                            if (data) 
                                marks.push(data[0]);

                             else 
                                callback(err, null);
                            

                    
                    callback(null,marks); // this is the function I wan to invoke
                                          // right after the for loop finishes so 
                                          // that i can get all marks of all 
                                          //students for a specific subject..   


    // currently it is undefined(marks[]) coz it goes straight for the callback 
     //  giving control to the for loop, the for loop gives data much later so that 
    // marks are not pushed to the array when I call it.

                 else 
                    callback(err, null);
                

            );
        

【讨论】:

能否请您对这两种方法详细说明一下 javascript本质上是异步的,所以你的forloop i值会增加,它不会等待内部函数完成,所以要么使用while循环你可以控制增量,或者使用ES6 async/await @987654321 @ 我已经编辑了第二个答案,你可能会遇到异步编译错误 在第二种方法中我得到一个像这样的编译错误 await Marks.find( subject_id: params.subject_id, student_base_id: student.base_no , 'student_base_id total', (err, data) => ^^^^^ drive.google.com/open?id=1SJIJF405gxp2FyH6b02ibTVrsCpkDCkv 这是堆栈跟踪

以上是关于我的回调与预期的节点 js 不同的主要内容,如果未能解决你的问题,请参考以下文章

如何将 synchronize.js 与节点的 fs.exists 一起使用?

节点js架构和性能

节点 SSH2 客户端连接会话

循环中的节点 JS 回调

我一直在我的节点代码中收到此错误。 DeprecationWarning:不建议在不回调的情况下调用异步函数

如何将节点中的异步回调添加到函数调用?