【问题标题】:javascript global variable questionjavascript全局变量问题
【发布时间】:2009-07-16 00:28:22
【问题描述】:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example: Simple Streetview Example</title>
<script src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=<?=APIKEY?>"
        type="text/javascript"></script>
<script type="text/javascript">

var myPano;
var newPoint;

function initialize() {
  var fenwayPark = new GLatLng(42.345573,-71.098326);
  var address = "1600 Amphitheatre Parkway, Mountain View, CA, USA";

  var geocoder = new GClientGeocoder();
    geocoder.getLatLng(
        address,
        function(point) {
            if (!point) {
                alert(address + " not found");
            } else {
                newPoint = point;
                alert("inside of function: " + newPoint);
            }
        });
    alert("outside of function: " + newPoint);
  panoramaOptions = { latlng:fenwayPark };
  myPano = new GStreetviewPanorama(document.getElementById("pano"), panoramaOptions);
  GEvent.addListener(myPano, "error", handleNoFlash);
}

function handleNoFlash(errorCode) {
  if (errorCode == FLASH_UNAVAILABLE) {
    alert("Error: Flash doesn't appear to be supported by your browser");
    return;
  }
}  
</script>

当我运行这段代码时,alert("outside of function: " + newPoint);没有得到任何值,但是在函数 alert("inside of function: " + newPoint);它得到了。

完整代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example: Simple Streetview Example</title>
<script src="http://maps.google.com/maps?file=api&amp;v=2.x&amp;key=ABQIAAAAgVzm2syhpm0A5rAKFMg3FBS-DTtkk0JB-Y_gKL-3MRZwBHch9RSjWJj17-fEEecjCvYeo1i7w_1yPw"
        type="text/javascript"></script>
<script type="text/javascript">

var myPano;

function initialize() {

    var geocoder = new GClientGeocoder();

    var address = "1600 Amphitheatre Parkway, Mountain View, CA, USA";
    geocoder.getLatLng(
        address,
        function(point) {
        if (!point) {
            alert(address + " not found");
        } else {
            panoramaOptions = { latlng:point };
            myPano = new GStreetviewPanorama(document.getElementById("pano"), panoramaOptions);
            GEvent.addListener(myPano, "error", handleNoFlash);
        }
    });
}

function handleNoFlash(errorCode) {
  if (errorCode == FLASH_UNAVAILABLE) {
    alert("Error: Flash doesn't appear to be supported by your browser");
    return;
  }
}  
</script>

我想在打开页面时显示地址:1600 Amphitheatre Parkway, Mountain View, CA, USA 的街景

【问题讨论】:

    标签: javascript google-maps


    【解决方案1】:

    内部函数是一个回调函数。意思是,它会等到 geocode api 调用完成运行后再执行。这称为异步执行。您会注意到外部警报在内部警报之前触发,即使内部警报是更早编写的。

    任何需要有效 newPoint 值的代码都需要在回调函数中执行,就像内部警报一样。

    【讨论】:

    • 我想我在这里吹毛求疵,但要说“在地理编码 api 调用完成运行时回调函数 等待”并不真正正确。实际上,当 getLatLang 完成其工作时,它会调用您的回调函数并返回结果。我相信你已经知道这一点,不知怎的,我的描述听起来不太对。
    • 我移动 myPano = new GStreetviewPanorama(document.getElementById("pano"),panoramaOptions); GEvent.addListener(myPano, "error", handleNoFlash);到函数内部,但什么也没发生..
    • 您预计会发生什么?能贴出完整的代码吗?
    • @SolutionYogi:我同意。这就是为什么它被称为“回调”。但是,我想避免混淆 OP。也许我做得过头了。
    【解决方案2】:

    getLatLng() 是异步的。

    您调用getLatLng(),一段时间后它会使用数据调用您的回调。在您调用 getLatLng() 之后,您的“函数外部”代码会立即被调用,异步调用您的“函数内部”回调发生之前。

    【讨论】:

      【解决方案3】:

      您解决了异步getLatLng() 的问题。您的新代码的唯一问题是您请求的地址没有全景图(取出“1600”,它会起作用)。有一个函数可以返回最近的全景点:getNearestPanoramaLatLng()。如果附近没有全景图,它将返回 null。以下是如何在您的代码中使用它:

      function initialize() {
      
          var geocoder = new GClientGeocoder();
          var panoClient = new GStreetviewClient();
      
          var address = "1600 Amphitheatre Parkway, Mountain View, CA, USA";
      
          geocoder.getLatLng(
          address,
          function(point) {
              if (!point) {
                  alert(address + " not found");
              } else {
                  panoClient.getNearestPanoramaLatLng(point, function(newPoint) {
                      if (newPoint == null) {
                          alert("no panorama found");
                          return;
                      }
                      panoramaOptions = { latlng:newPoint};
                      myPano = new GStreetviewPanorama(document.getElementById("pano"), panoramaOptions);
                      GEvent.addListener(myPano, "error", handleNoFlash);
                  });
              }
          });
      }
      

      【讨论】:

        【解决方案4】:

        因为调用内部警报的回调函数在外部警报之后运行。

        尝试将您的外部警报延迟一秒钟,您会看到正确的值会被提醒

        setTimeout(function(){ alert(newPoint); }, 1000);
        

        这是因为调用内部警报的函数是异步的

        编辑:请注意,上述做法是不好的做法,只能用于帮助您了解发生了什么以及为什么。

        【讨论】:

        • 虽然超时可以帮助刚接触异步编程的人更好地理解这个概念,但他们也应该小心意识到,在像 OP 这样的代码示例中使用它并不是一个好的技术。不保证异步调用会在 1 秒甚至 10 秒内完成(考虑非常慢的连接)。
        • 这绝对不是一个好主意。无法猜测异步函数需要多长时间。首先提供回调是有原因的。
        • 是的,我完全同意这两个 cmets,超时只是应该通过证明在调用外部警报时 var 未初始化来帮助他理解。除了测试目的之外,这种代码不应该用于任何其他目的......