NativeScript - 地理位置:使用getCurrentLocation承诺函数的正确方法
我正在编写一个使用nativescript-geolocation
API的简单应用程序。 函数getCurrentLocation基本上可以正常工作,但是当我移动到另一个名为maps-module.js
的文件并从文件detail.js
的主线程调用它时,它返回的对象位置为NULL。 打印后控制对象,我意识到变量returned_location是在函数完成查找位置之前返回的。 我认为它的多线程问题,但我真的不知道如何解决它。 这是我的文件。NativeScript - 地理位置:使用getCurrentLocation承诺函数的正确方法
detail.js
var Frame = require("ui/frame");
var Observable = require("data/observable");
var MapsModel = require("../../view-models/maps-model");
var defaultMapInfo = new MapsModel({
latitude: "10.7743332",
longitude: "106.6345204",
zoom: "0",
bearing: "0",
tilt: "0",
padding: "0"
});
var page;
var mapView;
exports.pageLoaded = function(args) {
page = args.object;
var data = page.navigationContext;
page.bindingContext = defaultMapInfo;
}
exports.onBackTap = function() {
console.log("Back to home");
var topmost = Frame.topmost();
topmost.goBack();
}
function onMapReady(args) {
mapView = args.object;
mapView.settings.zoomGesturesEnabled = true;
}
function onMarkerSelect(args) {
console.log("Clicked on " + args.marker.title);
}
function onCameraChanged(args) {
console.log("Camera changed: " + JSON.stringify(args.camera));
}
function getCurPos(args) {
var returned_location = defaultMapInfo.getCurrentPosition(); // variable is returned before function finished
console.dir(returned_location);
}
exports.onMapReady = onMapReady;
exports.onMarkerSelect = onMarkerSelect;
exports.onCameraChanged = onCameraChanged;
exports.getCurPos = getCurPos;
地图 - module.js
var Observable = require("data/observable");
var Geolocation = require("nativescript-geolocation");
var Gmap = require("nativescript-google-maps-sdk");
function Map(info) {
info = info || {};
var _currentPosition;
var viewModel = new Observable.fromObject({
latitude: info.latitude || "",
longitude: info.longitude || "",
zoom: info.zoom || "",
bearing: info.bearing || "",
tilt: info.bearing || "",
padding: info.padding || "",
});
viewModel.getCurrentPosition = function() {
if (!Geolocation.isEnabled()) {
Geolocation.enableLocationRequest();
}
if (Geolocation.isEnabled()) {
var location = Geolocation.getCurrentLocation({
desiredAccuracy: 3,
updateDistance: 10,
maximumAge: 20000,
timeout: 20000
})
.then(function(loc) {
if (loc) {
console.log("Current location is: " + loc["latitude"] + ", " + loc["longitude"]);
return Gmap.Position.positionFromLatLng(loc["latitude"], loc["longitude"]);
}
}, function(e){
console.log("Error: " + e.message);
});
if (location)
console.dir(location);
}
}
return viewModel;
}
module.exports = Map;
由于越来越位置是一个异步的过程,你应该viewModel.getCurrentPosition返回一个承诺,会看这样的事情,
viewModel.getCurrentPosition() {
return new Promise((resolve, reject) => {
geolocation
.getCurrentLocation({
desiredAccuracy: enums.Accuracy.high,
updateDistance: 0.1,
maximumAge: 5000,
timeout: 20000
})
.then(r => {
resolve(r);
})
.catch(e => {
reject(e);
});
});
}
,然后当你使用它,它看起来像这样
defaultMapInfo.getCurrentPosition()
.then(latlng => {
// do something with latlng {latitude: 12.34, longitude: 56.78}
}.catch(error => {
// couldn't get location
}
}
希望帮助:)
更新:BTW,geolocation.enableLocationRequest()也是asynchorous方法。
如果湿婆普拉萨德的注脚......
“geolocation.enableLocationRequest()也是asynchorous法”
...是正确的,那么返回的承诺通过geolocation.enableLocationRequest()
必须被处理适当的代码将会发生相当大的变化。
试试这个:
viewModel.getCurrentPosition = function(options) {
var settings = Object.assign({
'desiredAccuracy': 3,
'updateDistance': 10,
'maximumAge': 20000,
'timeout': 20000
}, options || {});
var p = Promise.resolve() // Start promise chain with a resolved native Promise.
.then(function() {
if (!Geolocation.isEnabled()) {
return Geolocation.enableLocationRequest(); // return a Promise
} else {
// No need to return anything here.
// `undefined` will suffice at next step in the chain.
}
})
.then(function() {
if (Geolocation.isEnabled()) {
return Geolocation.getCurrentLocation(settings); // return a Promise
} else { // <<< necessary to handle case where Geolocation didn't enable.
throw new Error('Geolocation could not be enabled');
}
})
.then(function(loc) {
if (loc) {
console.log("Current location is: " + loc.latitude + ", " + loc.longitude);
return Gmap.Position.positionFromLatLng(loc.latitude, loc.longitude);
} else { // <<< necessary to handle case where loc was not derived.
throw new Error('Geolocation enabled, but failed to derive current location');
}
})
.catch(function(e) {
console.error(e);
throw e; // Rethrow the error otherwise it is considered caught and the promise chain will continue down its success path.
// Alternatively, return a manually-coded default `loc` object.
});
// Now race `p` against a timeout in case enableLocationRequest() hangs.
return Promise.race(p, new Promise(function(resolve, reject) {
setTimeout(function() {
reject(new Error('viewModel.getCurrentPosition() timed out'));
}, settings.timeout);
}));
}
return viewModel;
注:
开始与解决本地无极链提供了多达包装相同的效果
new Promise(...)
但清洁主要是因为意想不到的内链抛出保证向链路的错误路径下发一个Error对象,而不需要try/catch/reject()
。此外,在标有“返回承诺”的两行中,我们不必关心我们是否返回承诺或价值;要么会被原生Promise链吸收。两个
else
条款是为了迎合不会自动抛出的失败案例。Promise.race()
应该不是必要的,但是可以防止报告here的问题。有可能内置的“超时”机制就足够了。这种额外的超时机制是一种“腰带和大括号”措施。包含一种机制,通过传递
options
对象来覆盖viewModel.getCurrentPosition
中的硬编码默认值。要使用默认值运行,只需致电viewModel.getCurrentPosition()
即可。此功能主要是为了允许settings.timeout
在Promise.race()
中重复使用。
Shiva Prasad的回答和你的工作像魅力一样。我也更了解Promise并处理异步,非常感谢XD。 – Sea
这两个答案之间的差异将在故障条件下出现。例如。在禁用地理位置的设备上进行测试。 –
这就是我要找的,我的代码现在非常简单,谢谢XD – Sea