如果用户在 3 秒后没有做出决定,如何检测用户位置权限超时?

问题描述 投票:0回答:5

我想在用户未决定位置权限后执行任务。我尝试了以下方法:

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 秒后没有做出决定?谢谢。


场景:

  1. 网站被用户打开 -> 出现位置提醒 -> 用户没有点击
    Allow
    Block
    长达 3 秒 ->
    Save dummy data location to database
    .
  2. 网站被用户打开 -> 位置提醒出现 -> 用户在 3 秒前点击
    Allow
    ->
    Save user data location to database
    .
  3. 网站被用户打开 -> 位置提醒出现 -> 用户在 3 秒前点击
    Block
    ->
    Save dummy data location to database
    .

约束条件:

  • 每个场景都不应该执行双重动作。
  • 如果用户曾经
    Allow
    Block
    ,然后执行适当的操作。
javascript browser location user-permissions navigator
5个回答
2
投票

需要说明的是,如果用户没有单击其中一个提示选项,听起来你想要做的是在 3 秒后关闭导航器地理定位提示。 这是不可能的。为什么?

navigator geolocation prompt 由浏览器控制,它不会暴露任何关闭弹出窗口的方法。

getCurrentPosition() 只有成功和错误处理程序,以及 maximumAge、timeout 和 enableHighAccuracy 的选项。超时选项有点误导,因为您可能认为它是针对用户输入的超时。不是这种情况。超时是针对点击接受后通过地理定位 api 进行的网络请求。

navigator.geolocation 只公开了三个方法:clearWatch()、getCurrentPosition() 和 watchPosition()。这些方法都不能中断 getCurrentPosition() 的调用。

进一步阅读表明,最佳做法是发出软提示,询问用户是否允许发出地理定位请求,理想情况下仅在某种用户输入之后(人们不喜欢在加载时跳到他们身上的提示) :

如果您仍想在加载时显示地理定位提示,如果用户未使用 setTimeout() 在提示上单击接受或拒绝,并且在成功或错误时使用 clearTimeout 清除它,则没有什么可以阻止您执行其他操作().你只是不能用 JS 关闭提示作为这些操作之一。


2
投票

我认为在这种情况下,我们的地理定位 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");
  });

多读书


1
投票

您可以在 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
}, {});

1
投票

通过一些代码更新你可以实现它,就像这样

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 }
);

0
投票

这是您可以使用的一些代码的完整示例,可以解决您的问题:

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();
© www.soinside.com 2019 - 2024. All rights reserved.