Node.js无法使用promises,Mongoose和GET请求推送到全局数组

时间:2016-01-29 00:38:53

标签: javascript arrays json node.js mongoose

我无法将我需要的结果推送到我在使用Q promise库创建的同步函数中定义的数组中。根据汽车品牌,用户位置的邮政编码和最大半径,此功能有3个任务:

  1. 查询我的经销商集合,以根据用户输入的特定制造商检索经销商ID。
  2. 然后我定义了一个数组:dealershipIDs。该阵列将用于推动某些经销商ID。然后,我遍历返回的经销商的json列表,以检索经销商及其邮政编码的个人ID名称。我向api服务发出GET请求,以计算用户输入的位置与任务1中找到的每个经销商之间的距离。如果经销商和用户之间的距离小于输入的半径,则该经销商的id名称将添加到数组中我想传递给第3步。我没有成功,因为我尝试传递的数组是空的,并且不包含for循环之外的id名称。
  3. 查询我的汽车收藏集,了解包含经销商ID列表的汽车。然后,最后一步将呈现适当的页面,其中汽车结果将显示在用户的区域中。
  4. 任务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);
        });
    }
    

    如何通过添加到dealershipIDs数组来使此功能正常工作,以便我可以将其传递给用于查询我的Cars集合?

    以下函数是我的HTTP请求,它返回从A点到B点的距离的JSON对象,即(距离: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
    

2 个答案:

答案 0 :(得分:0)

我猜的问题是因为在第二个任务中,getDistanceWithAPI是一个异步函数。因此,第二个任务将在任何getDistanceWithAPI解析之前快速返回。让我尝试使用preso代码来解决您的问题。它并不完美,因为它引入了一个全局数组,可能我们可以通过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);
    });

答案 1 :(得分: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);
    });
}

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

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提出建议将异步调用添加到promise数组并使用Q.all的巨大呐喊。这正是我所需要的。