JS全局变量没有在第一次迭代中设置 [英] JS global variable not being set on first iteration

查看:88
本文介绍了JS全局变量没有在第一次迭代中设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在处理一些代码后为全局变量赋值。它没有按计划运行。



我所做的是在两个文本框中输入地址和城市。它进入最后一个函数,并调用codeAddress获取地址的坐标。



从那里我发送坐标到setLatLng,它工作正常。但我无法使用getLatLng调用longlats来查看设置值。



如果我添加地址和城市两次,它只会显示一个值。我认为longlats正在初始化太迟,以至于我没有及时看到正确的价值。



有什么建议吗?



相关代码如下。

 < script> 
var longlats =;

函数setLatLng(x,y){
longlats = x +,+ y;
alert(longlats)//显示值
}

函数getLatLng(){
alert(longlats);
返回longlats;
//调用此函数给出undefined


函数codeAddress(){

$('#map')。show();
var geocoder = new google.maps.Geocoder();
var address = document.getElementById(address)。value +,+ document.getElementById(city)。value;

geocoder.geocode({'address':address},function(results,status){
if(status == google.maps.GeocoderStatus.OK){
var lat = results [0] .geometry.location.lat();
var lng = results [0] .geometry.location.lng();
locationsall [counter] = new Array();
locationsall [counter] [0] =地址;
locationsall [counter] [1] = lat; //有值$ b $ locationsall [counter] [2] = lng; //值
setLatLng(locationsall [counter] [1],locationsall [counter] [2]);

counter ++;

}

$ (function(){
$(#locationadd)。click(function(){
codeAddress();
var get = getLatLng(); // value is undefined ..
//我想用longlats中的值做些什么
}
)};

< / script>

Edit1

  $(#locationadd ).click(function(){
var address = $(#address)。val();
var city = $(#city).val();

if(address == || city ==){
$(#locationtext)。text('*请输入地址和城市');
返回false;

else {
codeAddress(function(){
var get = getLatLng();
var longlat = get.split(,);
var lat = longlat [0];
var lng = longlat [1];

var $ tr2 = $('< tr>')。css({
'padding':'4px',
'background-color':'#ddd'
})。appendTo('#locationDeals');

var location = [
地址,
city
];
locations.push(位置);

(i = 0; i <2; i ++){
var $ td2 = $('< td>)。appendTo($ tr2);
$('< span>).text(location [i])。appendTo($ td2 );
$('< input type =hidden>')。attr({
'name':'loc ['+ ctr +'] ['+ i +']' ,
'value':location [i]
})。appendTo($ td2);
}
var $ tdRemoveRow2 = $('< td>)。appendTo ($ tr2);
$('< a>')。attr({
'href':'#',
'id':'submit-button'
})。text(Remove)。click(function(){
var index2 = $ tr2 。指数();
$(#locationDeals input [type ='hidden'])。each(function(){
this.name = this.name.replace(/ \ [(\ d +)\\ \\] /,函数(str2,number2){
return[+(+ number2> index2 - 1?number2 - 1:number2)+];
});
});

$ tr2.remove();
var tmp = locations.splice(locations.indexOf(location),1);
deleteMarker(tmp);
返回false;
})。appendTo($ tdRemoveRow2);

ctr ++;
document.getElementById(address)。value =;
document.getElementById(city)。value =;
document.getElementById(address)。focus();
$(#locationtext)。text('');

返回false;
});
}
});


解决方案

问题是 geocoder。 geocode 是异步的。你不能这样做,因为你的 codeAddress 函数会在设置 longlats 之前返回。您需要更改自己的编码风格才能在Google地图返回结果后使用longlats。



您需要更改您的代码:

  $(#locationadd)。click(function(){
codeAddress();
var get = getLatLng(); //值是未定义的。
//我想用longlats中的值做些什么
}

至此:

  $(#locationadd)。click(function(){
codeAddress(function(){
var get = getLatLng();
//用longlats中的值做
});
});

为此,您需要将 copyAddress 更改为:

 函数codeAddress(callback){

/ *
* Some stuff
* /

geocoder.geocode({'address':address},function(results,status){
if(status == google.maps.GeocoderStatus.OK){
/ *
*一些东西
* /

setLatLng(locationsall [counter] [1],locationsall [counter] [2]);

callback(); //这是哪里/何时返回值
//所以这是我们想要执行代码的地方。

})
}






附加解释:

从您的评论看来,您仍然在尝试这样做:

  var val; 
codeAddress(function(){
val = getLatLng();
});
doStuffWith(val);

这是行不通的,因为codeAddress会返回执行前的getLatLng。您需要更改编码风格。你需要这样写:

  codeAddress(function(){
val = getLatLng();
doStuffWith(val);
});

也就是说,您需要将您在调用之后编写的所有代码移动到codeAddAddress函数INSIDE codeAddress

原因是代码执行的方式如下所示:




  • BROWSER ENTERS JAVASCRIPT PHASE:

      codeAddress被称为
    |
    |
    | -------------->里面的codeAdd地址请求谷歌地图
    |是制作一个回调函数
    |一旦它返回就被执行。
    v
    codeAddress返回
    请注意,此时getLatLng尚未被调用
    ,这是因为浏览器还没有向Google Maps请求
    ,因为它是仍然执行
    javascript引擎。
    |
    v
    在codeAddress被执行后编写的代码
    (请记住,Google地图的调用还没有发生)
    |
    v
    没有更多javascript执行


  • javascript阶段结束,BROWSER Enters DOM RENDERING PHASE

     如果有任何更改,DOM会更新并绘制在屏幕上。 


  • DOM渲染结束,BROWSER进入网络阶段

     (注意:实际上网络层是异步的)

    浏览器执行未决请求(图像,iframes,XMLHttprequest等)
    进行必要的网络连接并开始下载内容。
    |
    |
    v
    浏览器服务完成的请求和计划适当的事件
    (更新DOM,触发onreadystatechange等)
    请注意,此时没有实际发生javascript或DOM更新。
    浏览器在循环中执行某些操作,而不是递归执行。
    在这一点上,谷歌地图的请求已经完成。
    |
    v
    没有更多网络操作服务


  • 网络阶段结束,浏览器输入JAVASCRIPT PHASE

      google maps请求完成,onreadystatechange执行
    |
    |
    | ---->内部onreadystate将回调函数改为
    |谷歌地图API被称为
    | |
    | ----->在Google地图回调里面getLatLng
    |被调用,然后回调codeAddress
    |叫做。
    | |
    | ------>内部回调到
    | codeAddress你现在可以
    |使用返回的值。
    |这是你需要
    |的原因在此处移动您的所有代码。
    v
    没有更多javascript执行


  • javascript阶段结束,BROWSER ENTERS DOM RENDERING PHASE




并且事件循环继续。

<正如你所看到的,你不能简单地从codeAddress返回值。相反,您需要将代码移到codeAddress中,以便在正确的时间执行它。


I'm trying to give a global variable a value after some code is processed. It's not working as planned.

What I do is enter an address and city in two textboxes. It goes into the last function and calls codeAddress which gets the coordinates of the address.

From there i send the coordinates to setLatLng and it works fine. But i can't call longlats using the getLatLng to see the set value.

It'll only show a value if I add an address and city two times. I'm thinking the longlats are being initialized too late that I don't see the correct value in time.

Any advice?

Relevant code is below.

<script>
var longlats ="";

function setLatLng(x,y){
    longlats = x+","+y;
    alert(longlats) //shows value
}

function getLatLng(){
    alert(longlats);
    return longlats;
    //calling this gives undefined
}

function codeAddress() {

$('#map').show();
var geocoder = new google.maps.Geocoder();
var address = document.getElementById("address").value +"," + document.getElementById("city").value;

geocoder.geocode( { 'address': address}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
    var lat = results[0].geometry.location.lat();
    var lng = results[0].geometry.location.lng();
    locationsall[counter] = new Array();
    locationsall[counter][0] = address;
    locationsall[counter][1] = lat; //has value
    locationsall[counter][2] = lng; //has value
    setLatLng(locationsall[counter][1],locationsall[counter][2]);

counter++;

} 

$(function() {
$("#locationadd").click(function() {
   codeAddress();
   var get = getLatLng();//value is undefined..
  //i want to do stuff with the values in longlats
}
)};

</script>

Edit1

 $("#locationadd").click(function() {
var address = $("#address").val();
var city = $("#city").val();

if (address =="" || city =="") {
    $("#locationtext").text('*Please enter an address and city');
    return false;
} 
else {
    codeAddress(function(){
    var get = getLatLng();
    var longlat = get.split(",");
    var lat = longlat[0];
    var lng = longlat[1];

    var $tr2 = $('<tr>').css({
            'padding': '4px',
            'background-color': '#ddd'
    }).appendTo('#locationDeals');

    var location = [
            address,
            city
    ];
    locations.push(location);

    for (i = 0; i < 2; i++) {
        var $td2 = $('<td>').appendTo($tr2);
        $('<span>').text(location[i]).appendTo($td2);
        $('<input type="hidden">').attr({
            'name': 'loc[' + ctr + '][' + i + ']',
            'value': location[i]
        }).appendTo($td2);
    }
    var $tdRemoveRow2 = $('<td>').appendTo($tr2);
    $('<a>').attr({
        'href': '#',
        'id': 'submit-button'
    }).text("Remove").click(function() {
    var index2 = $tr2.index();
    $("#locationDeals input[type='hidden']").each(function() {
        this.name = this.name.replace(/\[(\d+)\]/, function(str2, number2) {
          return "[" + (+number2 > index2 - 1 ? number2 - 1 : number2) + "]";
        });
    });

    $tr2.remove();
    var tmp = locations.splice(locations.indexOf(location), 1);
    deleteMarker(tmp);
    return false;
    }).appendTo($tdRemoveRow2);

    ctr++;
    document.getElementById("address").value = "";
    document.getElementById("city").value = "";
    document.getElementById("address").focus();
    $("#locationtext").text('');

    return false;
    });
    } 
});

解决方案

The problem is geocoder.geocode is asynchronous. You can't do it the way you do because your codeAddress function will return before longlats is set. You need to change your coding style to use longlats only after google maps have returned the result.

You need to change your code from this:

$("#locationadd").click(function() {
   codeAddress();
   var get = getLatLng();//value is undefined..
  //i want to do stuff with the values in longlats
}

To this:

$("#locationadd").click(function() {
   codeAddress(function(){
     var get = getLatLng();
     //do stuff with the values in longlats
   });
});

In order to do that, you need to change copyAddress to:

function codeAddress(callback) {

  /*
   * Some stuff
   */

  geocoder.geocode( { 'address': address}, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      /*
       * Some stuff
       */

      setLatLng(locationsall[counter][1],locationsall[counter][2]);

      callback(); // This is where/when the values are returned
                  // so this is where/when we want to execute code.  
    } 
  })
}


Additional explanation:

From your comments, it appears that you're still trying to do this:

var val;
codeAddress(function(){
    val = getLatLng();
});
doStuffWith(val);

This won't work because codeAddress returns BEFORE getLatLng executes. You need to change the style of your coding. You need to write it like this:

codeAddress(function(){
    val = getLatLng();
    doStuffWith(val);
});

That is, you need to move all code that you would have written after the call to codeAddress to the function INSIDE codeAddress.

The reason for it is that the way the code executes is something like this:

  • BROWSER ENTERS JAVASCRIPT PHASE:

       codeAddress is called
              |
              |
              |--------------> inside codeAddress a request to google maps
              |                is made which registers a callback function
              |                to be executed once it returns.
              v
       codeAddress returns
       note that at this point getLatLng isn't called yet
       this is because the browser haven't made the request
       to google maps yet because it's still executing the
       javascript engine.
              |
              v
       code written after codeAddress is executed
       (remember, the call to google maps still haven't happened yet)
              |
              v
       no more javascript to execute
    

  • javascript phase ends, BROWSER ENTERS DOM RENDERING PHASE

       The DOM gets updated and drawn on screen if there are any changes.
    

  • DOM rendering ends, BROWSER ENTERS NETWORK PHASE

       (note: in reality the network layer is asynchronous)
    
       Browser executes pending requests (images, iframes, XMLHttprequest etc.)
       Makes the necessary network connections and begins downloading stuff.
              |
              |
              v
       Browser services completed requests and schedules appropriate events
       (update DOM, trigger onreadystatechange etc.)
       Note that at this point no javascript or DOM updates actually happens.
       The browser does things in a loop, not recursively.
       It is at this point that the google maps request is made.
              |
              v
       No more network operations to service
    

  • network phase ends, BROWSER ENTERS JAVASCRIPT PHASE

       google maps request completes, onreadystatechange executes
              |
              |
              |----> inside onreadystatechange the callback to the
              |      google maps API is called
              |             |
              |             '-----> inside the google maps callback getLatLng
              |                     is called, then the callback to codeAddress
              |                     is called.
              |                          |
              |                          '------> inside the callback to
              |                                   codeAddress you can now
              |                                   use the returned values.
              |                                   This is the reason you need
              |                                   to move all your code here.
              v
       no more javascript to execute
    

  • javascript phase ends, BROWSER ENTERS DOM RENDERING PHASE

and the event loop continues.

As you can see, you can't simply return the values from codeAddress. Instead you need to move your code inside codeAddress to have it executed at the right time.

这篇关于JS全局变量没有在第一次迭代中设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆