我想在用户未决定位置权限后执行任务。我尝试了以下方法:
navigator.geolocation.getCurrentPosition((pos) => {
let lat = pos.coords.latitude;
let long = pos.coords.longitude;
console.log(lat, long);
console.log("User granted permission");
}, (error) => {
console.error(error);
console.error("User didn't grant permission");
}, {
timeout: 3000,
maximumAge: 3000,
enableHighAccuracy: true
});
我已经将
timeout
和maximumAge
属性设置为3000
毫秒,但它不再起作用了。仅当用户关闭权限弹出窗口时才会触发该错误。如何检测用户是否在 3 秒后没有做出决定?谢谢。
场景:
Allow
或 Block
长达 3 秒 -> Save dummy data location to database
.Allow
-> Save user data location to database
.Block
-> Save dummy data location to database
.约束条件:
Allow
或Block
,然后执行适当的操作。需要说明的是,如果用户没有单击其中一个提示选项,听起来你想要做的是在 3 秒后关闭导航器地理定位提示。 这是不可能的。为什么?
navigator geolocation prompt 由浏览器控制,它不会暴露任何关闭弹出窗口的方法。
getCurrentPosition() 只有成功和错误处理程序,以及 maximumAge、timeout 和 enableHighAccuracy 的选项。超时选项有点误导,因为您可能认为它是针对用户输入的超时。不是这种情况。超时是针对点击接受后通过地理定位 api 进行的网络请求。
navigator.geolocation 只公开了三个方法:clearWatch()、getCurrentPosition() 和 watchPosition()。这些方法都不能中断 getCurrentPosition() 的调用。
进一步阅读表明,最佳做法是发出软提示,询问用户是否允许发出地理定位请求,理想情况下仅在某种用户输入之后(人们不喜欢在加载时跳到他们身上的提示) :
如果您仍想在加载时显示地理定位提示,如果用户未使用 setTimeout() 在提示上单击接受或拒绝,并且在成功或错误时使用 clearTimeout 清除它,则没有什么可以阻止您执行其他操作().你只是不能用 JS 关闭提示作为这些操作之一。
我认为在这种情况下,我们的地理定位 API 的 Promisification 将是一个很好的解决方案。
const getPosition = function () {
// this will return a new Promise which will then give us Position when it's fulfilled
return new Promise(function (resolve, reject) {
// solution-1: more simplified version
navigator.geolocation.getCurrentPosition(resolve, reject);
// solution-2:
// navigator.geolocation.getCurrentPosition(
// position => resolve(position),
// err => reject(err)
// );
});
};
// Simple Timeout function
const timeout = function (sec) {
// Here we just want to reject our promise so we can neglect resolve by replacing it with '_'
return new Promise(function (_, reject) {
setTimeout(function () {
reject(new Error('Request took too long!'));
}, sec * 1000);
});
};
// Promise.race accepts array of Promise and return the first fulfilled promise
Promise.race([getPosition(), timeout(3)])
.then(pos => {
let lat = pos.coords.latitude;
let long = pos.coords.longitude;
console.log(lat, long);
console.log('User granted permission');
})
.catch(error => {
console.error(error);
console.error("User didn't grant permission");
});
多读书
您可以在 getCurrentPosition 之前添加 setTimeout 调用,并在用户执行某些操作时清除 timeoutID:
var timeoutID = window.setTimeout(() => {
console.log('user makes no decision');
// do 1
}, 3000);
navigator.geolocation.getCurrentPosition((pos) => {
timeoutID && window.clearTimeout(timeoutID);
// do 2
}, (error) => {
timeoutID && window.clearTimeout(timeoutID);
// do 3
}, {});
通过一些代码更新你可以实现它,就像这样
navigator.geolocation.getCurrentPosition(
(pos) => {
// Handle successful geolocation request
let lat = pos.coords.latitude;
let long = pos.coords.longitude;
console.log(lat, long);
console.log("User granted permission");
},
(error) => {
if (error.code === error.TIMEOUT) {
console.error("Timeout error: User didn't grant permission within the specified time");
} else {
console.error(error);
console.error("User didn't grant permission");
}
},
{ timeout: 3000, maximumAge: 3000, enableHighAccuracy: true }
);
这是您可以使用的一些代码的完整示例,可以解决您的问题:
let timerId;
let permissionStatus;
function saveDummyLocation() {
// Save dummy data location to database
console.log("Saving dummy location...");
}
function saveUserLocation(position) {
// Save user data location to database
console.log("Saving user location:", position.coords.latitude, position.coords.longitude);
}
function onPermissionChange() {
if (permissionStatus.state === "granted") {
navigator.geolocation.getCurrentPosition(
(position) => {
saveUserLocation(position);
},
(error) => {
console.error(error);
saveDummyLocation();
}
);
} else if (permissionStatus.state === "denied") {
saveDummyLocation();
}
}
function checkPermission() {
navigator.permissions.query({ name: "geolocation" }).then((status) => {
permissionStatus = status;
permissionStatus.addEventListener("change", onPermissionChange);
if (permissionStatus.state === "prompt") {
timerId = setTimeout(() => {
permissionStatus.removeEventListener("change", onPermissionChange);
saveDummyLocation();
}, 3000);
} else {
onPermissionChange();
}
});
}
checkPermission();