异步in循环的问题

时间:2018-06-03 00:30:50

标签: javascript node.js

我需要:

1)提出两个请求

2)然后从请求中获取数据

3)并发送回复

我正在使用firebase数据库。我正在通过forEach从数据库中获取数据 我需要处理数据和响应数据(json)

任何人都可以帮我异步吗?或者帮助编写回调函数

我阅读了很多关于此的信息,但不明白

我的代码在这里工作得不好 我有异步问题 那么我该如何改进呢?

router.get('/places/all', function(req, res, next) {
    var lat = req.param('lat');
        lon = req.param('lon');
        result = [],
        resData = [];

    var query = firebase.database().ref('Places');
    var i = 0;
    var promise1 = new Promise(function(resolve, reject) {          
        query.on("value", function(snapshot) { 
            console.log(snapshot.numChildren())
            snapshot.forEach(function(childSnapshot) {
                childData = childSnapshot.val();

                var gmapApiKey = 'API_KEY';
                    placeID = childData.placeID;
                    language = req.param('lang');
                    url = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=' + placeID + '&key=' + gmapApiKey + '&language=' + language;
                    placeLat = childData.lat;
                    placeLon = childData.lon;
                    distanceMatrixApiUrl = 'https://maps.googleapis.com/maps/api/distancematrix/json?origins=' + lat + ',' + lon + '&destinations=' + placeLat + ',' + placeLon + '&key=' + gmapApiKey;

                i++;

                var requestDistance = new Promise(function(resolve, reject) {
                    https.get(distanceMatrixApiUrl, res => {
                        res.setEncoding("utf8");
                        let body = "";
                        res.on("data", data => {
                            body += data;
                        });
                        res.on("end", () => {
                            body = JSON.parse(body);
                            resolve(body);
                        });
                    });
                    console.log(requestDistanceApi)
                    requestDistance = Promise.resolve(requestDistanceApi)
                });
                var requestPlaces = new Promise(function(resolve, reject) {
                    https.get(url, res => {
                        res.setEncoding("utf8");
                        let body = "";
                        res.on("data", data => {
                            body += data;
                        });
                        res.on("end", () => {
                            i++;
                            result = JSON.parse(body);
                            resolve(result);
                        });
                    });
                    console.log(requestPlaceApi)
                    requestPlaces = Promise.resolve(requestPlacesApi)
                    i++;
                });
                requestDistance.then(function(valueDistance) {
                    requestPlaces.then(function(valuePlace) {
                        resData.push({
                            name: valuePlace.result.name,
                            address: valuePlace.result.vicinity,
                            open_now: valuePlace.result.opening_hours.open_now,
                            weekday_text: valuePlace.result.opening_hours.weekday_text,
                            latitude: valuePlace.result.geometry.location.lat,
                            longitude: valuePlace.result.geometry.location.lng,
                            distance: valueDistance.rows[0].elements[0].distance.text,
                        });

                    }).catch((error) => {
                        assert.isNotOk(error,'Promise Places error');
                        done();
                    }); 
                }).catch((error) => {
                    assert.isNotOk(error,'Promise Distance error');
                    done();
                }); 



            });
        });
    });
    promise1.then(function(value) {

        res.send(value);

    }).catch((error) => {
        assert.isNotOk(error,'Promise error');
        done();
    }); 
});

1 个答案:

答案 0 :(得分:0)

我不会重写这一切,而是会给你一个大纲。

首先,firebase SDK提供了承诺,而不是使用回调。使用它们而不是添加新的Promise来包装它们。这将有助于简化代码结构并使整个承诺链更简单

我不确定哪个包htts.get()来自哪个,但它很可能有承诺。转换为使用那些

另一个技巧是将2个嵌套请求合并为一个可以使用Promise.all()

完成的promise。

所以这是基本的代码大纲。请注意,我没有太多关注您希望如何处理所有这些数据以便发送给客户端。您需要根据需要进行调整

您可能希望将整个代码块分解为更小的函数,以使逻辑更容易理解

另请注意,我没有添加任何错误处理catch(),这将取决于您

// use firebase promise instead of callback
var mainpromise = query.on("value").then(function(snapshot) {

  var subPromises = [];


  snapshot.forEach(function(childSnapshot) {
    //childData = ...

    // look into https promises instead of wrapping in `new Promise
    var placesPromise new Promise(function(resolve, reject) {
      https.get(distanceMatrixApiUrl, res => {
        // .....
        res.on("end", () => {
          body = JSON.parse(body);
          resolve(body);
        });
      });
    });

    var distancePromise = new Promise.... // similar to above

    // combine these promises into one
    var combinedPromise = Promise.all([placesPromise, distancePromise]).then(function(resultsArray) {
      var places = resultsArray[0],
        distances = resultsArray[1];
      //assign above to childData or whatever you want to do with them
      return childData;// or return processed results or skip this `then and do all processing in the next then() commented below

    })
    // store combined promises in array
    subPromises.push(combinedPromise);

  });

  // return promise to resolve mainPromise
  return Promise.all(subPromises)// might need a `then()` here to return processed data depending on structure you want returned

});

mainPromise.then(function(results) {
  // process and send results which is array of all the childData from snapshot.forEach 

    res.send(processedData);

})