javascript - NativeScript - 地理位置 : right way to use getCurrentLocation promise function

标签 javascript android promise geolocation nativescript

我正在编写一个使用 nativescript-geolocation API 的简单应用程序。 函数 getCurrentLocation 基本上工作正常,但是当我移动到另一个名为 maps-module.js 的文件并从文件 detail.js 的主线程调用它时,对象位置它返回为 NULL。 打印控制台对象后,我意识到变量 returned_location 在函数完成查找位置之前返回。 我认为这是多线程问题,但我真的不知道如何解决。 这是我的文件。

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;

ma​​ps-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;

最佳答案

如果 Shiva Prasad 的脚注 ...

"geolocation.enableLocationRequest() is also an asynchorous method"

... 是正确的,那么 geolocation.enableLocationRequest() 返回的 Promise 必须适当处理,代码将发生相当大的变化。

试试这个:

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;

注释:

  1. 使用已解析的 native Promise 启动链与包装在 new Promise(...) 中的效果大致相同,但更清晰主要是因为链中的意外抛出保证交付错误对象在链的错误路径下,无需 try/catch/reject()。此外,在标记为“return a Promise”的两行中,我们无需关心返回的是 Promise 还是值;两者都将被本地 Promise 链同化。

  2. 包含两个 else 子句以应对不会自动抛出的失败情况。

  3. Promise.race() 不是必需的,但它是针对报告的问题的保障 here .内置的“超时”机制可能就足够了。这种额外的超时机制是一种“腰带式”措施。

  4. 包含一种机制,通过传递 options 对象来覆盖 viewModel.getCurrentPosition 中的硬编码默认值。要使用默认值运行,只需调用 viewModel.getCurrentPosition()。引入此功能主要是为了允许 settings.timeoutPromise.race() 中重用。

编辑:

感谢@grantwparks 提供Geolocation.isEnabled() 也返回 Promise 的信息。

现在我们可以使用 p = Geolocation.isEnabled().... 启动 Promise 链并测试异步传递的 bool 值。如果 false 则尝试启用。

从那时起,如果地理定位最初启用或已经启用,Promise 链的成功路径将被遵循。启用地理定位的进一步测试消失了。

这应该有效:

viewModel.getCurrentPosition = function(options) {
    var settings = Object.assign({
        'desiredAccuracy': 3,
        'updateDistance': 10,
        'maximumAge': 20000,
        'timeout': 20000
    }, options || {});

    var p = Geolocation.isEnabled() // returned Promise resolves to true|false.
    .then(function(isEnabled) {
        if (isEnabled) {
            // No need to return anything here.
            // `undefined` will suffice at next step in the chain.
        } else {
            return Geolocation.enableLocationRequest(); // returned Promise will cause main chain to follow success path if Geolocation.enableLocationRequest() was successful, or error path if it failed;
        }
    })
    .then(function() {
        return Geolocation.getCurrentLocation(settings); // return Promise
    })
    .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 Geolocation.isEnabled() or Geolocation.enableLocationRequest() hangs.
    return Promise.race(p, new Promise(function(resolve, reject) {
        setTimeout(function() {
            reject(new Error('viewModel.getCurrentPosition() timed out'));
        }, settings.timeout);
    }));
}
return viewModel;

关于javascript - NativeScript - 地理位置 : right way to use getCurrentLocation promise function,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47237688/

相关文章:

javascript - 您如何使用 esbuild 捆绑导出全局变量?

javascript - 将回调附加到充当一次触发的全局事件的 promise 的概念是否有一个名称? (如 $(document).ready())

javascript - 检测用户的手势,例如滑动

javascript - 如何等待 Google 客户端库中的所有 promise 得到解决

javascript - 在全局 Javascript 变量中保存临时表单信息

javascript - 即使我确实处理了未处理的 promise 拒绝

java - 来自数据库的微调器 - 首先添加空值

Android Google SignIn 结果为空

javascript - 为什么这个错误没有出现在我的 Redux Action 的 Catch 中?

javascript - Node JS 的 Promises 数组仍处于 <pending> 状态