我需要帮助我正在制作的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
});
})
});
});
答案 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
})
注意:我建议传递参数或返回回调中的lat
和lon
,而不是使用lat
和lon
提取全局范围,但这样可行仍然。