2017-05-19 46 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到舊版瀏覽器上運行。