Javascript 如果用户拒绝在 Firefox 中共享地理位置,则永远不会调用函数失败

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5947637/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 19:38:37  来源:igfitidea点击:

function fail never called if user declines to share geolocation in firefox

javascriptfirefoxcallbackgeolocation

提问by theRealWorld

So I have this javascript code. In safari and chrome, if user declines to share location, it goes to fail function as it should; however, in Firefox, it does not.

所以我有这个javascript代码。在 safari 和 chrome 中,如果用户拒绝共享位置,它应该会失败;然而,在 Firefox 中,它没有。

Any helps appreciated.

任何帮助表示赞赏。

function initGeolocation()
{
    if( navigator.geolocation )
    {          
          // Call getCurrentPosition with success and failure callbacks
          navigator.geolocation.getCurrentPosition( success, fail );
    }
    else
    {
          alert("Sorry, your browser does not support geolocation services.");
    }
}

 var map;
 function success(position)
 {

     var longIDText = document.getElementById('longID');
     var latIDText = document.getElementById('latID');
     longIDText.value = position.coords.longitude;
     latIDText.value = position.coords.latitude;
     document.getElementById('coordSubmitID').click();
  }

  function fail(error)
  {
          alert("FAAAAAAAAAAIIIIIIIIIL")
          var zip_code ;
          while (true){
              // Could not obtain location

              zip_code = prompt("Please enter your current address or zip code","");


              if ( zip_code == "" ) {
                  alert(zip_code +" is not a valid address. Please try again.");
              } 
              else{
                break;
              }
          }
          var zipIDText = document.getElementById('zipID');
          zipIDText.value = zip_code;
          document.getElementById('coordSubmitID').click();
  }

采纳答案by Alex K.

For Firefox it seems thatPERMISSION_DENIEDis raised onlyif "Never share" is selected; if the dialog is dismissed or "Not now" is selected, effectively nothing happens - even on mozillas geolocation demoif you dismiss the permissions UI nothing happens.

对于 Firefox,似乎只有在选择“从不共享”时才会PERMISSION_DENIED引发;如果对话框被关闭或“不是现在”被选择,实际上什么也不会发生 - 即使在mozillas 地理定位演示中,如果您关闭权限 UI,也不会发生任何事情。

This means that getCurrentPositioncan return either because the user closed the confirmation UI, or because it successfully started it asynchronous request - there doesn't appear to be a way to discriminate between the two.

这意味着getCurrentPosition可以返回,因为用户关闭了确认 UI,或者因为它成功启动了异步请求 - 似乎没有办法区分两者。

https://bugzilla.mozilla.org/show_bug.cgi?id=675533

https://bugzilla.mozilla.org/show_bug.cgi?id=675533

回答by Jamie

This is a real pain, and definately not desirable functionality.

这是一个真正的痛苦,绝对不是理想的功能。

The workaround I am using to save the user waiting for ever is to set a timeout to check if the wait spinner is showing after 3 seconds, and if so, hide it and show a manual zip code input:

我用来保存用户等待的解决方法是设置超时以检查等待微调器是否在 3 秒后显示,如果是,隐藏它并显示手动邮政编码输入:

var latlng;

var waitTime = 3000;
try {
    if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError);
    } else {
        showError("NOT-SUPPORTED");
    }
    var t = setTimeout(function () {
        if ($("#getZip div.loading").css("display") != "none") {
            $("#getZip div.loading").hide();
            $("#errorZip").show();
        }
    }, waitTime);
} catch (evt) {
    alert(evt);
}

回答by GFoley83

As alexleonard pointed out, the only reliable, cross-browser solution I've found for this is to have a setTimeout()to check the state of your latLngobject/variables, as the timeoutoption of getCurrentPosition()doesn't seem to work reliably. The example below was tested in IE11, Chrome33 and Firefox28.

正如 alexleonard 指出的那样,我为此找到的唯一可靠的跨浏览器解决方案是setTimeout()检查latLng对象/变量的状态,因为 的timeout选项getCurrentPosition()似乎无法可靠地工作。下面的示例在 IE11、Chrome33 和 Firefox28 中进行了测试。

For a more complete solution that uses a jQuery promise, check out my Gist here: https://gist.github.com/GFoley83/10092929

有关使用 jQuery 承诺的更完整解决方案,请在此处查看我的要点:https: //gist.github.com/GFoley83/10092929

Example - Hit F12, paste into the console and run

示例 - 按 F12,粘贴到控制台并运行

var latLng,
    geoOptions = {
        enableHighAccuracy: false,
        timeout: 5000, // Wait 5 seconds
        maximumAge: 300000 //  Valid for 5 minutes
    };

var userLocationFound = function(position){
    latLng = {
        lat: position.coords.latitude,
        lng: position.coords.longitude
    };
    window.console.log("User confirmed! Location found: " + latLng.lat + ", " + latLng .lng);
}

var userLocationNotFound = function(){
    latLng = {
        lat: -41.29247, // fallback lat 
        lng: 174.7732  // fallback lng
    };
    window.console.log("Fallback set: ", latLng);
}

window.navigator.geolocation.getCurrentPosition(userLocationFound, userLocationNotFound, geoOptions);

setTimeout(function () {
    if(!latLng){
        window.console.log("No confirmation from user, using fallback");
        userLocationNotFound();
    }else{
        window.console.log("Location was set");
    }
}, geoOptions.timeout + 1000); // Wait extra second

回答by Chris

This is as per design and apparently is a non-issue. See https://bugzilla.mozilla.org/show_bug.cgi?id=675533

这是按照设计,显然不是问题。见https://bugzilla.mozilla.org/show_bug.cgi?id=675533

It is left to the developers using the feature to come up with a browser-specific work around for Firefox.

使用该功能的开发人员可以为 Firefox 提供特定于浏览器的解决方案。

Of note, based on the comment by the FF developer about actual geolocation usage by end users, apparently the Firefox developers are gathering detailed data about what end users are doing with their products.

值得注意的是,根据 FF 开发人员对最终用户实际地理定位使用情况的评论,显然 Firefox 开发人员正在收集有关最终用户使用其产品进行操作的详细数据。

回答by alexleonard

Note that this is actually also an issue in Chrome.

请注意,这实际上也是 Chrome 中的一个问题。

In Chrome an advisory notice appears "site wants to know your location" - it then offers "Allow" and "Deny" as options. With the UI design, the user is more likely to choose either Allow or Deny, which will then return an answer to the navigator.geolocation.getCurrentPosition function. However, the user can also click an "X" on the far right of the advisory notice. This is essentially the same as clicking "Not now" in Firefox.

在 Chrome 中,会出现一条建议通知“站点想要知道您的位置” - 然后提供“允许”和“拒绝”作为选项。通过 UI 设计,用户更有可能选择 Allow 或 Deny,然后这将向 navigator.geolocation.getCurrentPosition 函数返回答案。但是,用户也可以单击咨询通知最右侧的“X”。这与在 Firefox 中单击“Not now”基本相同。

No result is returned to the function.

没有结果返回给函数。

Looks like a timer has to be implemented to allow for this possible outcome.

看起来必须实现计时器才能实现这种可能的结果。

回答by Leblanc Meneses

Use a promise. I'm using angularjs that has it's own version of $q to solve the same issue we are all having.

使用承诺。我正在使用具有自己版本的 $q 的 angularjs 来解决我们都遇到的相同问题。

            $scope.ByUserPosition = function () {
                //http://www.w3.org/TR/geolocation-API/
                var deferred = $q.defer();

                deferred.promise.then(findByPosition, function (data) {
                    console.log('error', data);
                });

                var resolveBy = 1000 * 30;
                navigator.geolocation.getCurrentPosition(function (position) {
                    deferred.resolve({ latitude: position.coords.latitude, longitude: position.coords.longitude });
                }, function (err) {
                    deferred.reject(err);
                }, {
                    enableHighAccuracy: true,
                    timeout: resolveBy,
                    maximumAge: 0
                });

                $timeout(function() {
                    deferred.reject('timed out');
                }, resolveBy)
            };

回答by AMustafa

The only solution to this problem is as follows:

这个问题的唯一解决方案如下:

  1. When the user clicks the button to get his location automatically, show the spinner and a link beside it "ex: Cancel".
  2. If he enables sharing location, then no problem. If he decides to dismiss Firefox popup, the spinner would still be shown but he can click "Cancel" link to stop the spinner an an indicator for dismissing the popup
  1. 当用户单击按钮以自动获取他的位置时,显示微调器和它旁边的链接“例如:取消”。
  2. 如果他启用共享位置,那么没问题。如果他决定关闭 Firefox 弹出窗口,仍会显示微调器,但他可以单击“取消”链接停止微调器,这是关闭弹出窗口的指示器

I hope this helps :)

我希望这有帮助 :)

回答by michel.iamit

Edit (after a downvote) 6-11-2013

编辑(投反对票后)6-11-2013

As remarked below this answer, this does not solve the problem when a user denies access to location. To the downvote is correct. I keep the answer here, because the timeout is soemthing one should use anyway, and I do not see it in any answer.

正如此答案下面所述,当用户拒绝访问位置时,这并不能解决问题。投反对票是正确的。我将答案保留在这里,因为超时是无论如何都应该使用的东西,而且我在任何答案中都没有看到它。

The function navigator.geolocation.getCurrentPosition() has the option to send the timeout with it:

函数 navigator.geolocation.getCurrentPosition() 可以选择发送超时:

navigator.geolocation.getCurrentPosition(
     function (position){
        //do someting with position
     },
     function (error){
        // do something with the error (like the code)
     }, 
     {timeout:10000}
);

and some other options, like the age of the cached position (maximumAge). the timeout and maximumage are in milliseconds, so 10000 = 10 secs.

以及其他一些选项,例如缓存位置的年龄(maximumAge)。超时和最大值以毫秒为单位,因此 10000 = 10 秒。

By the way, the default timeout is infinite... so if you do not set the timeout, it will never call the callback for errors....

顺便说一句,默认超时是无限的......所以如果你不设置超时,它永远不会调用错误的回调......

so in the option like Jamie answered, I would say:

所以在杰米回答的选项中,我会说:

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(function (position) {
            success(position);
        }, showError, {timeout:3000});
    }

回答by Harry Moreno

Here's a solution to my problem using vanilla es6 Promises. Inspired by @LeblancMeneses response.

这是使用 vanilla es6 解决我的问题的方法Promises。受到@LeblancMeneses 回应的启发。

if(navigator.geolocation) {
  let promise = new Promise((resolve, reject) => {
    navigator.geolocation.getCurrentPosition(
      (position) => {
        resolve(position)
      },
      (error) => {
        resolve(error)
      }
    )
    window.setTimeout(() => {
      resolve({})
    }, 8000)
  })
  promise.then((result) => {
      // do something with result
  })
} else {
  console.log('no geolocation available')
}

回答by tahir-masood

watchPosition and getCurrentPosition both accept a second callback which is invoked when there is an error. The error callback provides an argument for an error object. For permission denied, error.code would be error.PERMISSION_DENIED (numeric value 1).

watchPosition 和 getCurrentPosition 都接受在出现错误时调用的第二个回调。错误回调为错误对象提供了一个参数。对于权限被拒绝,error.code 将是 error.PERMISSION_DENIED(数值 1)。

Read more here: https://developer.mozilla.org/en/Using_geolocation

在此处阅读更多信息:https: //developer.mozilla.org/en/Using_geolocation

Example:

例子:

navigator.geolocation.watchPosition(function(position) {
  console.log("i'm tracking you!");
},
function (error) { 
  if (error.code == error.PERMISSION_DENIED)
     console.log("you denied me :-(");

});

});