NodeJS 中的同步地理编码
Synchronous geocoding in NodeJS
是否可以等待异步调用 (geocode.reverseGeocode)?我想遍历目录中的 JPG 文件,从它们的 EXIF 数据中获取纬度和经度,并进行反向地理编码以获取拍摄这些照片的国家/城市。最后它需要在文件中添加一个 OSX 标签。但是我需要多次 运行 NodeJS 脚本来获取所有标签。 (因为文件迭代器不等待地理编码过程)。等待此请求的最佳解决方案是什么?
你可以在这里找到我的代码:
https://github.com/Acoustics/jbTagify/blob/development/index.js
提前致谢
处理多个异步调用的一种简单方法是使用 promises,无需同步 运行 它们并等待一个完成。您可以使用 Node 中可用的本机承诺,也可以使用诸如 bluebird 之类的承诺库,它可以 promisify 其他执行异步操作的库。
最简单的用例看起来像
var Promise = require("bluebird");
var geocoder = Promise.promisifyAll(require('geocoder'))
geocoder.geocodeAsync("Atlanta, GA")
.then(function(data){
var lat = data.results[0].geometry.location.lat;
var lng = data.results[0].geometry.location.lng;
console.log("Coordinates for Atlanta, GA: " + lat + "," + lng);
});
你在其中使用 promisified 函数 geocodeAsync
(原始函数名 + Async
),returns 承诺将返回的数据作为解析值。
在您想要执行多个异步代码的情况下,您可以轻松地创建一个承诺数组,然后让它们 运行 并行并在所有承诺都得到解决后处理结果。
var citiesToGeocode = ["Miami, FL", "New York", "Orlando, FL", "Rio de Janeiro, Brazil"];
var geocodePromises = [];
for (var i = 0; i < citiesToGeocode.length-1; ++i) {
geocodePromises.push(geocoder.geocodeAsync(citiesToGeocode[i]));
}
Promise.all(geocodePromises).then(function(result) {
result.forEach(function(geocodeResponse){
console.log("Coordinates for " + geocodeResponse.results[0].formatted_address +": " + geocodeResponse.results[0].geometry.location.lat + "," + geocodeResponse.results[0].geometry.location.lng);
});
});
使用相同的方法,您可以使用 reverseGeocodeAsync
从坐标中查找信息。
这是我的代码。如您所见,我需要一组根级别的承诺。我的 objective 是获取包含文件名及其地理编码数据的承诺集合。
var
_ = require('lodash'),
path = require('path'),
pkg = require(path.join(__dirname, 'package.json')),
fs = require('fs'),
promise = require('bluebird'),
exif = require('exif').ExifImage,
geocoder = promise.promisifyAll(require('geocoder')),
exec = require('child_process').exec,
config = require('nconf').file({
file: path.join(__dirname, 'config.json')
});
var geocodePromises = []; // I want to collect all promises here
fs.readdir(path.join(__dirname, 'files'), function (err, files) {
files.filter(function (file) {
var ext = file.split('.').pop(),
cond;
cond = file; // File needs to exist
cond = cond && file[0] != '.'; // Exclude hidden files
cond = cond && config.get("files:support").indexOf(ext) > -1; // File needs to be supported
return cond;
}).forEach(function (file) {
file = path.join(__dirname, 'files/') + file;
new exif({
image: file
}, function (err, data) {
if (!err) {
if (data.gps) {
var location = parseGPS(data.gps); // Obtain lat & lng
geocodePromises.push(geocoder.reverseGeocodeAsync(location.lat, location.lng));
} else {
console.log("Error: GPS data not available");
}
} else {
console.log("Error: " + err);
}
});
});
Promise.all(geocodePromises).then(function (result) {
console.log(result); // Returns an empty array []
// Each result should contain the filename and geocoded location
/*
Example:
{
"file": "1.jpg",
"location": {
<google reverseGeocode object>
}
}
*/
});
//exec('killall Finder');
});
function parseGPS(gps) {
var lat = gps.GPSLatitude,
lng = gps.GPSLongitude,
latRef = gps.GPSLatitudeRef || "N",
lngRef = gps.GPSLongitudeRef || "W";
// Convert coordinates to WGS84 decimal
lat = (lat[0] + lat[1] / 60 + lat[2] / 3600) * (latRef == "N" ? 1 : -1);
lng = (lng[0] + lng[1] / 60 + lng[2] / 3600) * (lngRef == "W" ? -1 : 1);
// Return lat, lng
return {
lat,
lng
};
};
是否可以等待异步调用 (geocode.reverseGeocode)?我想遍历目录中的 JPG 文件,从它们的 EXIF 数据中获取纬度和经度,并进行反向地理编码以获取拍摄这些照片的国家/城市。最后它需要在文件中添加一个 OSX 标签。但是我需要多次 运行 NodeJS 脚本来获取所有标签。 (因为文件迭代器不等待地理编码过程)。等待此请求的最佳解决方案是什么?
你可以在这里找到我的代码: https://github.com/Acoustics/jbTagify/blob/development/index.js
提前致谢
处理多个异步调用的一种简单方法是使用 promises,无需同步 运行 它们并等待一个完成。您可以使用 Node 中可用的本机承诺,也可以使用诸如 bluebird 之类的承诺库,它可以 promisify 其他执行异步操作的库。
最简单的用例看起来像
var Promise = require("bluebird");
var geocoder = Promise.promisifyAll(require('geocoder'))
geocoder.geocodeAsync("Atlanta, GA")
.then(function(data){
var lat = data.results[0].geometry.location.lat;
var lng = data.results[0].geometry.location.lng;
console.log("Coordinates for Atlanta, GA: " + lat + "," + lng);
});
你在其中使用 promisified 函数 geocodeAsync
(原始函数名 + Async
),returns 承诺将返回的数据作为解析值。
在您想要执行多个异步代码的情况下,您可以轻松地创建一个承诺数组,然后让它们 运行 并行并在所有承诺都得到解决后处理结果。
var citiesToGeocode = ["Miami, FL", "New York", "Orlando, FL", "Rio de Janeiro, Brazil"];
var geocodePromises = [];
for (var i = 0; i < citiesToGeocode.length-1; ++i) {
geocodePromises.push(geocoder.geocodeAsync(citiesToGeocode[i]));
}
Promise.all(geocodePromises).then(function(result) {
result.forEach(function(geocodeResponse){
console.log("Coordinates for " + geocodeResponse.results[0].formatted_address +": " + geocodeResponse.results[0].geometry.location.lat + "," + geocodeResponse.results[0].geometry.location.lng);
});
});
使用相同的方法,您可以使用 reverseGeocodeAsync
从坐标中查找信息。
这是我的代码。如您所见,我需要一组根级别的承诺。我的 objective 是获取包含文件名及其地理编码数据的承诺集合。
var
_ = require('lodash'),
path = require('path'),
pkg = require(path.join(__dirname, 'package.json')),
fs = require('fs'),
promise = require('bluebird'),
exif = require('exif').ExifImage,
geocoder = promise.promisifyAll(require('geocoder')),
exec = require('child_process').exec,
config = require('nconf').file({
file: path.join(__dirname, 'config.json')
});
var geocodePromises = []; // I want to collect all promises here
fs.readdir(path.join(__dirname, 'files'), function (err, files) {
files.filter(function (file) {
var ext = file.split('.').pop(),
cond;
cond = file; // File needs to exist
cond = cond && file[0] != '.'; // Exclude hidden files
cond = cond && config.get("files:support").indexOf(ext) > -1; // File needs to be supported
return cond;
}).forEach(function (file) {
file = path.join(__dirname, 'files/') + file;
new exif({
image: file
}, function (err, data) {
if (!err) {
if (data.gps) {
var location = parseGPS(data.gps); // Obtain lat & lng
geocodePromises.push(geocoder.reverseGeocodeAsync(location.lat, location.lng));
} else {
console.log("Error: GPS data not available");
}
} else {
console.log("Error: " + err);
}
});
});
Promise.all(geocodePromises).then(function (result) {
console.log(result); // Returns an empty array []
// Each result should contain the filename and geocoded location
/*
Example:
{
"file": "1.jpg",
"location": {
<google reverseGeocode object>
}
}
*/
});
//exec('killall Finder');
});
function parseGPS(gps) {
var lat = gps.GPSLatitude,
lng = gps.GPSLongitude,
latRef = gps.GPSLatitudeRef || "N",
lngRef = gps.GPSLongitudeRef || "W";
// Convert coordinates to WGS84 decimal
lat = (lat[0] + lat[1] / 60 + lat[2] / 3600) * (latRef == "N" ? 1 : -1);
lng = (lng[0] + lng[1] / 60 + lng[2] / 3600) * (lngRef == "W" ? -1 : 1);
// Return lat, lng
return {
lat,
lng
};
};