NodeJS Express:如何在将对象发送到响应之前完全构建对象?

时间:2016-11-11 02:17:46

标签: javascript node.js express

我正在尝试构建一个result_arr个位置对象作为响应发送,但我不确定如何仅在构建整个数组时发送响应。响应包含一个空数组,但在已发送响应后填充result_arr数组。

function handle_getLocations(req, res, done){
var con_id = req.body["contractor_id"];
console.log("Contractor ID :" + con_id.toString());
var result_arr = new Array();

employee.getActiveByContractor(con_id, function(err, employees){
    if (err) {
        console.log("Logging error in json:\n");
        res.json({"code" : 100, "status" : "Error in connection database"});
        return;
    };

    if(employees.length === 0) done(null);

    for(var i=0;i<employees.length;i++){
        assignment.getLocationsByEmployeeID(employees[i].employee_id, function(err, locations){
            if (err) {
                console.log("Logging error in json:\n");
                res.json({"code" : 100, "status" : "Error in connection database"});
                return;
            };
            console.log("Number of locations: " + locations.length.toString());
            for(var j=0;j<locations.length;j++){
                console.log("Assignment is: " + locations[j].assignment_id.toString());
                location.getAllByID(locations[j].location_id, function(err, loc){
                    if (err) {
                        console.log("Logging error in json:\n");
                        res.json({"code" : 100, "status" : "Error in connection database"});
                        return;
                    };

                    var loc_obj = {};
                    loc_obj.display_name = loc[0].display_name;
                    loc_obj.location_id = loc[0].location_id;
                    console.log("Location is: " + loc_obj.display_name);
                    console.log("Location ID is: " + loc_obj.location_id.toString());

                    result_arr.push(loc_obj);
                    console.log(result_arr);
                    done(result_arr);
                });
            };
        });
    };
});

};

我知道在nodejs中的想法是不进行阻塞调用,但我不确定如何确保在响应中发送所有信息。

3 个答案:

答案 0 :(得分:1)

您在循环中调用了许多异步函数,并且没有任何逻辑来检查它们何时完成以将响应发送回客户端。

我稍微修改了你的代码,以VannilaJS的方式添加逻辑,下面的代码非常混乱但工作代码。

  

无论如何我建议你使用基于promise的/异步模块   像asyncbluebird等处理这个很好。使用它们,你   可以提高代码的可读性和易维护性   摆脱callback hells和其他缺点。

async http://caolan.github.io/async/

bluebird https://github.com/petkaantonov/bluebird

您可以在以下链接中了解更多相关信息,

https://strongloop.com/strongblog/node-js-callback-hell-promises-generators/

function handle_getLocations(req, res, done){
   var con_id = req.body["contractor_id"];
   console.log("Contractor ID :" + con_id.toString());
   var result_arr = new Array();

   employee.getActiveByContractor(con_id, function(err, employees){
    if (err) {
        console.log("Logging error in json:\n");
        res.json({"code" : 100, "status" : "Error in connection database"});
        return;
    };

    if(employees.length === 0) done(null);

    var employeesChecked = 0;
    var errors = [];

    function sendResponse(){
       if(employeesChecked === employees.length) {
       res.json(result_arr);
       //done(result_arr);  // If required, uncomment this line and comment the above line
      }
    }

    for(var i=0;i<employees.length;i++){
        assignment.getLocationsByEmployeeID(employees[i].employee_id, function(err, locations){
            var locationsChecked = 0;
            if (err) {
                console.log(err);
                errors.push(err);
                ++employeesChecked;

                sendResponse();
            } else {
            console.log("Number of locations: " + locations.length.toString());
            for(var j=0;j<locations.length;j++){
                console.log("Assignment is: " + locations[j].assignment_id.toString());
                location.getAllByID(locations[j].location_id, function(err, loc){
                    ++locationsChecked;
                    if (err) {
                        console.log(err);
                        errors.push(err);
                    } else {
                    var loc_obj = {};
                    loc_obj.display_name = loc[0].display_name;
                    loc_obj.location_id = loc[0].location_id;
                    console.log("Location is: " + loc_obj.display_name);
                    console.log("Location ID is: " + loc_obj.location_id.toString());

                    result_arr.push(loc_obj);
                    console.log(result_arr);
                   }

                   if(locationsChecked === locations.length) {
                      ++employeesChecked;
                   }

                   sendResponse();
                });
            }
          }
        });
    }
});

}

答案 1 :(得分:0)

为了不在请求 - 响应生命周期中消耗太多时间,您需要将单个端点中的每个逻辑分开,但有时候根据您的情况,您可能需要更多地访问数据库而不是获取依赖于另一个的数据的时间,所以假设employee.getActiveByContractor返回承诺并且因为它是异步方法,所以你需要像.then这样链接它:

 employee.getActiveByContractor(con_id)
        .then(function(employees) {

另外,您需要阅读Promise

答案 2 :(得分:0)

正如Basim所说,这是使用Promises的好时机。

getLocationsByEmployeeIDgetAllByID是异步的,因此在循环结束时您将无法完成这些操作并发送您的回复。

Promise内置于最新的Node.js版本中。 在这里学习:https://www.udacity.com/course/javascript-promises--ud898

建议:

  1. getLocationsByEmployeeIDgetAllByID
  2. 创建承诺包装器
  3. 使用Promise.all确保每个getLocationsByEmployeeIDgetAllByID完整
  4. 在Promise.all的“成功”回调中返回您的http响应