具有异步Node.js和检索数据的Api数据使其同步

时间:2017-05-19 18:25:18

标签: javascript node.js callback

我需要帮助我正在制作的Node天气应用程序。我使用Google API来获取地址的经度和纬度,并将其提供给Dark Sky API,以JSON格式返回天气。

我的问题是,在谷歌API返回经度和纬度之前,大多数情况下天气API会进行搜索。我知道为什么它这样做是因为Node的异步性质。我的问题是如何让这部分同步呢?

var express = require('express');
var https = require('https')
var bodyParser = require("body-parser");

var app = express();

app.use(bodyParser.urlencoded({
extended: true
}));

app.use(bodyParser.json());

var lon;

var lat;

app.post('/', function(req,res,next){

var search = req.body.search;


function google(){

    var api = "API-KEY";

    var url = https.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${search}&key=${api}`, function(res3){

        var body = "";
        var googleResults;

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

        res3.on('end', function(){

            googleResults = JSON.parse(body);
            //console.log(body);
            lat = googleResults.results[0].geometry.location.lat;
            lon = googleResults.results[0].geometry.location.lon;
            console.log(search);
        })

    });

}


google();

//connectc to API URL()
var request = https.get(`https://api.darksky.net/forecast/API-KEY/${lon},${lat}`, function(res2){

console.log(lon + " " + lat)
            var body = "";
            var weather;
            //Read the data
            res2.on('data', function(data){
                body += data.toString();

            })

            res2.on('end', function(){
                    //Parse the data
                     weather = JSON.parse(body);
                    //Print data
                    //console.log("test = " + weather.currently.temperature)
                    res.render('index', {
                        temperature: weather.currently.temperature,
                        humidity: weather.currently.humidity,
                        wind: weather.currently.windSpeed
                    });
            })

});



});

3 个答案:

答案 0 :(得分:2)

最简单的做法是在不重构代码的情况下,让google()将回调函数作为参数。然后你可以使用那个回调函数来触发对黑暗天空的调用。



var express = require('express');
var https = require('https')
var bodyParser = require("body-parser");

var app = express();

app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(bodyParser.json());

app.post('/', function(req, res, next) {

  var search = req.body.search;

  // Have google() take a callback function as an argument and
  // call that function with the data when it's done.
  function google(cb) {

    var api = "API-KEY";

    var url = https.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${search}&key=${api}`, function(res3) {

      var body = "";
      var googleResults;

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

      res3.on('end', function() {

        googleResults = JSON.parse(body);
        //console.log(body);
        lat = googleResults.results[0].geometry.location.lat;
        lon = googleResults.results[0].geometry.location.lon;
        // Call the function here
        cb(lat, lon);
      })

    });

  }

  // Now use the callback to do your second request to darksky
  google(function(lat, lon) {
    //connectc to API URL()
    var request = https.get(`https://api.darksky.net/forecast/API-KEY/${lon},${lat}`, function(res2) {

      console.log(lon + " " + lat)
      var body = "";
      var weather;
      //Read the data
      res2.on('data', function(data) {
        body += data.toString();

      })

      res2.on('end', function() {
        //Parse the data
        weather = JSON.parse(body);
        //Print data
        //console.log("test = " + weather.currently.temperature)
        res.render('index', {
          temperature: weather.currently.temperature,
          humidity: weather.currently.humidity,
          wind: weather.currently.windSpeed
        });
      })

    });
  }});


});




答案 1 :(得分:0)

这不是解决问题的最简单或最平易近人的方式,但我一直在使用await关键字和node-fetch库来执行这些类型的请求。

基本上node-fetch适用于Promises,这意味着您可以使用它来发出请求,并在请求完成后使用.then()执行某些操作。 await关键字将所有嵌套转换为类似同步的代码,这意味着它更容易阅读和保留。以下是您的代码使用它们的方式:

var express = require('express');
var https = require('https')
var bodyParser = require("body-parser");

var app = express();

app.use(bodyParser.urlencoded({
  extended: true
}));

app.use(bodyParser.json());

var lon;
var lat;

app.post('/', (req, res, next) => {
  var search = req.body.search;
  async function google() {

    var api = "";
    var googleResults = await (await fetch(`https://maps.googleapis.com/maps/api/geocode/json?address=${search}&key=${api}`)).json()

    lat = googleResults.results[0].geometry.location.lat;
    lon = googleResults.results[0].geometry.location.lon;
    console.log(search)
  }
});


(async() => await google())();

//connectc to API URL()
var weather = await (await fetch(`https://api.darksky.net/forecast/7c41453dc9e5976eecb6a38487427b58/${lon},${lat}`)).json();
console.log(lon + " " + lat)
res.render('index', {
  temperature: weather.currently.temperature,
  humidity: weather.currently.humidity,
  wind: weather.currently.windSpeed
});

问题在于,由于await是ES6的一部分,您可能需要使用babel之类的东西在旧版浏览器上运行它。

答案 2 :(得分:-1)

在这里利用NodeJS的异步特性(使用节点式回调,承诺等)

例如,只需向您的google函数添加一个回调参数,并且在触发回调之后再运行您的http请求。例如,您的google功能可能会变成以下内容,然后您调用google并在回调中运行以下代码:

function google(callback){
    callback = callback || function() {}

    var api = "API-KEY";

    var url = https.get(`https://maps.googleapis.com/maps/api/geocode/json?address=${search}&key=${api}`, function(res3){

        var body = "";
        var googleResults;

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

        res3.on('end', function(){

            googleResults = JSON.parse(body);
            //console.log(body);
            lat = googleResults.results[0].geometry.location.lat;
            lon = googleResults.results[0].geometry.location.lon;
            console.log(search);
            callback()
        })

    });

}

google(function() {
    //execute your request and subsequent calls and app logic here
})

注意:我建议传递参数或返回回调中的latlon,而不是使用latlon提取全局范围,但这样可行仍然。