2017-05-19 45 views
1

我需要帮助我正在创建一个节点天气应用程序。我使用Google API来获取地址的经纬度,并将其反馈到Dark Sky API中,以便以JSON格式返回天气。Api数据与异步的Node.js和检索数据使其同步

我的问题是,在谷歌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 
        }); 
      }) 

}); 



}); 
+0

你不能让它同步!一种选择是只有在google结果完成后才调用天气api –

+0

您在本文中发布了您的API密钥,它在编辑中被删除,但仍然公开曝光。你应该撤消它并重新发布一个新密钥。 – Adam

+0

@亚当谢谢我已经有了,应该在发布之前加倍检查。 – monkeyman905

回答

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

您在此帖子中发布了您的API密钥,该密钥在编辑中被删除,但仍然公开曝光。你应该撤消它并重新发布一个新密钥。 – Adam

+0

哦,他原本在复制它时发布了他的API密钥。 –

+0

糟糕,我检查了您的解决方案,但没有看到。谢谢。 – Adam

-1

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

例如,只需添加一个回调参数您google功能和不运行你的http请求直到回调被触发。例如,您的谷歌功能可能成为以下内容,然后调用谷歌和运行在回调下面的代码:

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拉你的全球范围,但这仍然有效。

0

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

基本上node-fetch适用于承诺,这​​意味着您可以使用它做出请求,并使用.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到旧版浏览器上运行。