2016-01-29 20 views
1

我无法将我需要的结果推送到我在使用Q promise库创建的同步函数中定义的数组中。有3个任务,此功能基于汽车制造,用户的位置邮政编码,最大半径:Node.js无法使用promise,Mongoose和GET请求推送到全局数组

  1. 查询我的经销店集合检索基于特定制造商的用户ID经销店已经进入。
  2. 然后我定义一个数组:dealershipIDs。这个数组将被用来推动某些经销商id到。然后,我遍历返回的经销商json列表,检索经销商的个人id名称及其邮政编码。我向api服务发出GET请求,以计算用户输入位置与任务1中找到的每个经销商之间的距离。如果经销商与用户之间的距离小于输入的半径,则将该经销商的id名称添加到阵列我想传递给步骤3.我没有成功执行此操作,因为我试图传递的数组是空的,并且不包含for循环之外的id名称。
  3. 查询包含经销商ID列表的汽车的Cars集合。然后这个最后一步就会在用户所在的区域显示适当的页面,并显示汽车结果。

任务2是我的问题。我能够将正确的代理商ID添加到我定义的数组中,但是我无法将该数组传递给下一个。因为该数组在for循环之外是空的。

我一直被困在这个问题上多天,现在我已经尝试了一切。请让我知道,如果我可以更具体。

exports.getCarIndexPage = function(req, res) { 
    var m = req.session.make; // User input 
    var zipcode = req.session.zipcode; // User input 
    var radius = req.session.radius; // User input 
    req.session.valid = null; // Resets session variable 

    Dealership.find({makes: m}).exec() 
    .then(function (ids) { 
     var dealershipIDs = []; /* Trying to add dealer ids to array */ 
     ids.forEach(function (id) { 
      var id = ids[i]; 
      getDistanceWithAPI(zipcode, id.zip, function(distanceVal) { 
       console.log("This is the distance: " + distanceVal.distance); 
       if (distanceVal.distance <= radius) { 
        console.log("Adding " + id._id + " to array"); 
        dealershipIDs.push(id._id); // Adding dealership's id to array 
        console.log("Size of dealership array: " + dealershipIDs.length); 
       } 
       console.log("Inside for loop = Size of dealership array: " + dealershipIDs.length); /* Recognizes the array size! */ 
      }) 
     }) 
     console.log("Outside for loop = Size of dealership array: " + dealershipIDs.length); /* Does not recognize array size */ 
     return dealershipIDs; /* Return this array that contains the dealership ids */ 
    }).then(
     function (resultArray) { 
      Car.find({dealership_id: { $in: resultArray }}).exec() 
       .then(function (cars) { 
        console.log(cars); 
       }), 
       function (error) { 
        console.log("Could not iterate through through cars: " + error); 
       } 
    }, function (error) { 
     console.error("Error with the outer promises:", error); 
    }); 
} 

如何通过添加到经销商IDID数组以使我可以通过它来查询我的Cars集合,从而使此函数可以工作?

下面的函数是我的HTTP请求,并将其返回的距离的JSON对象从A点到B点,即(距离:1.664}

function getDistanceWithAPI(userInput, dealerZip, callback) { 
https.get('https://www.zipcodeapi.com/rest/xApFwnm4tosuL2gX2UDQIGcknN2NIHyfhXVNlhRPFkjrmzpou2edJry7fAVXhtdz/distance.json/' 
     + userInput + '/' + dealerZip + '/mile', function(res) { 
    var body = ''; // Will contain the final response 

    res.on('data', function(data){ 
    body += data; 
    }); 

    // After the response is completed, parse it and log it to the console 
    res.on('end', function() { 
    var parsed = JSON.parse(body); 
    callback(parsed); // i.e. returns {distance : 1.664 } 
    }); 
}) 

// If any error has occured, log error to console 
.on('error', function(e) { 
    console.log("Got error: " + e.message); 
}); 
} 

这是我的日志:

Server running at http://localhost:3000/ 
Outside for loop = Size of dealership array: 0 
[] 
This is the distance: 1.664 
Adding bmwofsf to array 
Size of dealership array: 1 
Inside for loop = Size of dealership array: 1 
This is the distance: 13.685 
Adding bmwofsanrafael to array 
Size of dealership array: 2 
Inside for loop = Size of dealership array: 2 
+0

问题出在第二个任务,getDistanceWithAPI是一个异步函数。因此,在getDistanceWithAPI有机会运行之前,第二项任务将很快返回。 – Ron

+0

您可以包含来自失败运行的日志输出吗?看起来你没有在返回'dealershipIDs'之前等待'getDistanceWithAPI'完成。 –

+0

@SimonMᶜKenzieEdit包括失败运行的日志。 –

回答

0
exports.getCarIndexPage = function(req, res) { 
var m = req.session.make; 
var zipcode = req.session.zipcode; 
var radius = req.session.radius; 
req.session.valid = null; // Resets session variable 

Dealership.find({makes: m}).exec() 
    .then(function (ids) { 
     var promises = []; 
     ids.forEach(function (id) { 
      /* Pushing ascynchrounous functions into promise array */ 
      promises.push(getDistanceWithQPromise(zipcode, id.zip, id._id)); 
     }); 
     return Q.all(promises) 
      .then(function (promise) { 
       var dealershipIDs = []; /* Adding dealership ids to array */ 
       promise.forEach(function (promiseData) { 
        var distance = promiseData.distance; 
        var id = promiseData.id; 
        if (distance <= radius) { 
         console.log("Adding " + id + " to array"); 
         dealershipIDs.push(id); // Adding dealership's id to array 
        } 
       }); 
       console.log("Outside for loop = Size of dealership array: " + dealershipIDs.length); /* Does recognize array size */ 
       return dealershipIDs; 
      }, function (err) { 
       console.log(err) 
      }); 
    }).then(function (resultArray) { // Receives the dealership Id array 
      Car.find({dealership_id: { $in: resultArray }}).exec() 
       .then(function (cars) { 
        renderResult(res, req, cars); 
       }), 
       function (error) { 
        console.log("Could not iterate through through cars: " + error); 
       } 
    }, function (error) { 
     console.error("Error with the outer promises:", error); 
    }); 
} 

有那么它返回使用Q库的承诺修改我的GET请求。我还必须将经销商ID添加到返回的响应中,以便我可以在getCarIndexPage中将其作为承诺值进行访问。

function getDistanceWithQPromise(userInput, dealerZip, dealerID) { 
var deferred = Q.defer(); 
var request = https.request('https://www.zipcodeapi.com/rest/xApFwnm4tosuL2gX2UDQIGcknN2NIHyfhXVNlhRPFkjrmzpou2edJry7fAVXhtdz/distance.json/' 
     + userInput + '/' + dealerZip + '/mile', function(response) { 
    var responseData = ''; 
    response.on('data', function (data) { 
     responseData += data; 
    }); 

    /* Adding the dealer ID to the response string so that I can convert it to JSON before returning the promise */ 
    response.on('end', function() { 
     responseData = responseData.slice(0, -1); 
     responseData += "," + '"id":' + '"'+dealerID+'"' + "}"; 

     deferred.resolve(JSON.parse(responseData)); 
    }); 

    }); 

    request.on('error', function(err) { 
      deferred.reject(err); 
    }); 

    request.end(); 
    return deferred.promise; 
}; 

对Ron提出巨大的嘘声,建议将异步调用添加到承诺数组并使用Q.all。那正是我需要的。

0

我想这个问题是因为在第二个任务中,getDistanceWithAPI是一个异步函数,因此,在任何getDistanceWithAPI解析之前,第二个任务会很快返回,我试着用preso代码来解决你的问题,但这并不完美,因为它引入了全球阵列,可能是我们可以提高i通过玩Q.all一点点。

var dealershipIDs = []; /* put it outside, because the results in 2nd tasks is used to indicated the finished state. */ 
Dealership.find({makes: m}).exec() 
    .then(function (ids) { 
     var promises = [] 
     for (var i = 0; i < ids.length; i++) { 
      var id = ids[i]; 
      promises.push(getDistanceWithAPI(zipcode, id.zip, function(distanceVal) { // Returns promise 
       console.log("This is the distance: " + distanceVal.distance); 
       if (distanceVal.distance <= radius) { 
        console.log("Adding " + id._id + " to array"); 
        dealershipIDs.push(id._id); // Adding dealership's id to array 
        console.log("Size of dealership array: " + dealershipIDs.length); 
       } 
       console.log("Inside for loop = Size of dealership array: " + dealershipIDs.length); /* Recognizes the array size! */ 
      })); 
     } 
     console.log("Outside for loop = Size of dealership array: " + dealershipIDs.length); /* Does not recognize array size */ 
     return Q.all(promises); // resolve all promises and return; 
    }).then(
     function() { 
      var resultArray = dealershipIDs; 
      Car.find({dealership_id: { $in: resultArray }}).exec() 
       .then(function (cars) { 
        console.log(cars); 
       }), 
       function (error) { 
        console.log("Could not iterate through through cars: " + error); 
       } 
    }, function (error) { 
     console.error("Error with the outer promises:", error); 
    }); 
+0

我喜欢你的答案在哪里。我没有想到定义一个promise数组,然后使用'return Q.all(promises)'。无论出于何种原因,它将继续在任务2中挂起。我将继续探索Q.all的建议并回复您。 –